From 895861493c27b56590b014fa7e69623f4edf3080 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Tue, 29 Aug 2023 01:26:08 +0200 Subject: [PATCH 01/19] Verification process --- .../BBRAPIModuleVerfication.csproj | 15 +++ BBRAPIModuleVerfication/Program.cs | 107 ++++++++++++++++++ BBRAPIModules/ModuleAttribute.cs | 20 ++++ BattleBitAPIRunner.sln | 6 + BattleBitAPIRunner/Module.cs | 25 +++- 5 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj create mode 100644 BBRAPIModuleVerfication/Program.cs create mode 100644 BBRAPIModules/ModuleAttribute.cs diff --git a/BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj b/BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj new file mode 100644 index 0000000..af16098 --- /dev/null +++ b/BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs new file mode 100644 index 0000000..1ac2925 --- /dev/null +++ b/BBRAPIModuleVerfication/Program.cs @@ -0,0 +1,107 @@ +using BattleBitAPIRunner; +using Newtonsoft.Json; + +namespace BBRAPIModuleVerfication; + +internal class Program +{ + static void Main(string[] args) + { + if (args.Length != 1) + { + Console.WriteLine("Usage: BBRAPIModuleVerfication "); + return; + } + + string filePath = args[0]; + + Module module; + try + { + module = new Module(filePath); + } + catch (Exception e) + { + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + return; + } + + List modules = new(); + List newModules = new() { module }; + DependencyListResponse dependencyFiles; + do + { + Console.WriteLine(JsonConvert.SerializeObject(new DependencyListResponse() { Dependencies = newModules.SelectMany(m => m.RequiredDependencies).Distinct().ToArray() })); + dependencyFiles = JsonConvert.DeserializeObject(Console.In.ReadToEnd()); + modules.AddRange(newModules); + newModules.Clear(); + newModules.AddRange(dependencyFiles.Dependencies.Select(x => new Module(x))); + } while (newModules.Count > 0); + + ModuleDependencyResolver dependencies = new(modules.ToArray()); + try + { + + + } + catch (Exception e) + { + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + return; + } + + try + { + Module[] allModules = dependencies.GetDependencyOrder().ToArray(); + + module.Compile(); + } + catch (Exception e) + { + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, module.Name, module.Description, module.Version, module.RequiredDependencies, module.OptionalDependencies, e.Message))); + return; + } + } +} + +public enum ResponseType +{ + DependencyList, + VerificationResult +} + +public interface IResponse +{ + public ResponseType ResponseType { get; } +} + +internal class VerificationResponse : IResponse +{ + public ResponseType ResponseType => ResponseType.VerificationResult; + + public VerificationResponse(bool success, string name, string description, string version, string[] requiredDependencies, string[] optionalDependencies, string errors) + { + this.Success = success; + this.Name = name; + this.Description = description; + this.Version = version; + this.RequiredDependencies = requiredDependencies; + this.OptionalDependencies = optionalDependencies; + this.Errors = errors; + } + + public bool Success { get; set; } + public string? Name { get; set; } + public string? Description { get; set; } + public string? Version { get; set; } + public string[]? RequiredDependencies { get; set; } + public string[]? OptionalDependencies { get; set; } + public string? Errors { get; set; } +} + +internal class DependencyListResponse : IResponse +{ + public ResponseType ResponseType => ResponseType.DependencyList; + + public string[] Dependencies { get; set; } +} \ No newline at end of file diff --git a/BBRAPIModules/ModuleAttribute.cs b/BBRAPIModules/ModuleAttribute.cs new file mode 100644 index 0000000..b033a29 --- /dev/null +++ b/BBRAPIModules/ModuleAttribute.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BBRAPIModules; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class ModuleAttribute : Attribute +{ + public string Description { get; set; } + public string Version { get; set; } + + public ModuleAttribute(string description, string version) + { + this.Description = description; + this.Version = version; + } +} diff --git a/BattleBitAPIRunner.sln b/BattleBitAPIRunner.sln index 7bc842d..80b3ede 100644 --- a/BattleBitAPIRunner.sln +++ b/BattleBitAPIRunner.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BattleBitAPIRunner", "Battl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BBRAPIModules", "BBRAPIModules\BBRAPIModules.csproj", "{B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BBRAPIModuleVerfication", "BBRAPIModuleVerfication\BBRAPIModuleVerfication.csproj", "{2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}.Debug|Any CPU.Build.0 = Debug|Any CPU {B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}.Release|Any CPU.Build.0 = Release|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index cf65d95..335e29e 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -1,4 +1,5 @@ -using BBRAPIModules; +using BattleBitAPI.Common; +using BBRAPIModules; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -14,6 +15,8 @@ using System.Threading.Tasks; using System.Xml.Linq; +[assembly: InternalsVisibleTo("BBRAPIModuleVerfication")] + namespace BattleBitAPIRunner { internal class Module @@ -25,6 +28,8 @@ internal class Module public AssemblyLoadContext? Context { get; private set; } public Type? ModuleType { get; private set; } public string? Name { get; private set; } + public string? Description { get; private set; } + public string? Version { get; private set; } public string[]? RequiredDependencies { get; private set; } public string[]? OptionalDependencies { get; private set; } public byte[] AssemblyBytes { get; private set; } @@ -63,6 +68,7 @@ private void initialize() this.syntaxTree = CSharpSyntaxTree.ParseText(code, null, this.ModuleFilePath, Encoding.UTF8); this.Name = this.getName(); this.getDependencies(); + this.getMetadata(); Console.Write("Module "); Console.ForegroundColor = ConsoleColor.White; @@ -72,6 +78,23 @@ private void initialize() Console.WriteLine(); } + private void getMetadata() + { + IEnumerable attributeSyntaxes = syntaxTree.GetRoot().DescendantNodes().OfType(); + IEnumerable moduleAttributes = attributeSyntaxes.Where(x => x.Name.ToString() + "Attribute" == nameof(ModuleAttribute)); + if (moduleAttributes.Count() != 1) + { + throw new Exception("Module must have exactly one ModuleAttribute"); + } + + AttributeSyntax moduleAttribute = moduleAttributes.First(); + IEnumerable moduleAttributeArguments = moduleAttribute.ArgumentList?.Arguments ?? throw new Exception("ModuleAttribute must have arguments"); + AttributeArgumentSyntax descriptionArgument = moduleAttributeArguments.ElementAtOrDefault(0) ?? throw new Exception("ModuleAttribute must have a description argument"); + AttributeArgumentSyntax versionArgument = moduleAttributeArguments.ElementAtOrDefault(1) ?? throw new Exception("ModuleAttribute must have a version argument"); + this.Description = descriptionArgument.Expression.ToString().Trim('"'); + this.Version = versionArgument.Expression.ToString().Trim('"'); + } + private void getDependencies() { IEnumerable attributeSyntaxes = syntaxTree.GetRoot().DescendantNodes().OfType(); From 82ad02ceb509328fc35750015e3b0f46d4bc97a2 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Tue, 29 Aug 2023 11:38:40 +0200 Subject: [PATCH 02/19] this won't work --- BBRAPIModuleVerfication/Program.cs | 34 ++++++++++++++++--- .../Properties/launchSettings.json | 8 +++++ BattleBitAPIRunner/Module.cs | 4 +-- 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 BBRAPIModuleVerfication/Properties/launchSettings.json diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs index 1ac2925..db0b29c 100644 --- a/BBRAPIModuleVerfication/Program.cs +++ b/BBRAPIModuleVerfication/Program.cs @@ -1,10 +1,34 @@ using BattleBitAPIRunner; +using BBRAPIModules; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis; using Newtonsoft.Json; +using Microsoft.CodeAnalysis.CSharp; +using System.Text; namespace BBRAPIModuleVerfication; internal class Program { + static string readUntilEOT() + { + StringBuilder inputBuffer = new StringBuilder(); + int readByte; + + while ((readByte = Console.Read()) != -1) + { + if (readByte == 228)//4) + { + break; + } + + char character = (char)readByte; + inputBuffer.Append(character); + } + + return inputBuffer.ToString(); + } + static void Main(string[] args) { if (args.Length != 1) @@ -38,11 +62,11 @@ static void Main(string[] args) newModules.AddRange(dependencyFiles.Dependencies.Select(x => new Module(x))); } while (newModules.Count > 0); - ModuleDependencyResolver dependencies = new(modules.ToArray()); + Module[] allModules; try { - - + ModuleDependencyResolver dependencies = new(modules.ToArray()); + allModules = dependencies.GetDependencyOrder().ToArray(); } catch (Exception e) { @@ -52,8 +76,6 @@ static void Main(string[] args) try { - Module[] allModules = dependencies.GetDependencyOrder().ToArray(); - module.Compile(); } catch (Exception e) @@ -62,6 +84,8 @@ static void Main(string[] args) return; } } + + } public enum ResponseType diff --git a/BBRAPIModuleVerfication/Properties/launchSettings.json b/BBRAPIModuleVerfication/Properties/launchSettings.json new file mode 100644 index 0000000..756f479 --- /dev/null +++ b/BBRAPIModuleVerfication/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "BBRAPIModuleVerfication": { + "commandName": "Project", + "commandLineArgs": "E:\\Create\\Development\\Software\\C#\\BattleBit\\BattleBitBaseModules\\ModeratorTools.cs" + } + } +} \ No newline at end of file diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index 335e29e..ba0a7fb 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -37,8 +37,8 @@ internal class Module public string ModuleFilePath { get; } public Assembly? ModuleAssembly { get; private set; } - private SyntaxTree syntaxTree; - private string code; + internal SyntaxTree syntaxTree; + internal string code; public static void UnloadContext() { From 1517bece5eb340148b06619446b338d0e2b95cf5 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Tue, 29 Aug 2023 14:29:41 +0200 Subject: [PATCH 03/19] This works --- BBRAPIModuleVerfication/Program.cs | 86 +++++----------- .../Properties/launchSettings.json | 2 +- BattleBitAPIRunner/Module.cs | 98 +++++++++++++++---- 3 files changed, 105 insertions(+), 81 deletions(-) diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs index db0b29c..f05a1a6 100644 --- a/BBRAPIModuleVerfication/Program.cs +++ b/BBRAPIModuleVerfication/Program.cs @@ -5,30 +5,12 @@ using Newtonsoft.Json; using Microsoft.CodeAnalysis.CSharp; using System.Text; +using System.Collections.ObjectModel; namespace BBRAPIModuleVerfication; internal class Program { - static string readUntilEOT() - { - StringBuilder inputBuffer = new StringBuilder(); - int readByte; - - while ((readByte = Console.Read()) != -1) - { - if (readByte == 228)//4) - { - break; - } - - char character = (char)readByte; - inputBuffer.Append(character); - } - - return inputBuffer.ToString(); - } - static void Main(string[] args) { if (args.Length != 1) @@ -39,6 +21,8 @@ static void Main(string[] args) string filePath = args[0]; + Module.logToConsole = false; + Module module; try { @@ -46,37 +30,41 @@ static void Main(string[] args) } catch (Exception e) { - Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, Path.GetFileNameWithoutExtension(filePath), null, null, null, null, e.Message))); return; } - List modules = new(); - List newModules = new() { module }; - DependencyListResponse dependencyFiles; - do - { - Console.WriteLine(JsonConvert.SerializeObject(new DependencyListResponse() { Dependencies = newModules.SelectMany(m => m.RequiredDependencies).Distinct().ToArray() })); - dependencyFiles = JsonConvert.DeserializeObject(Console.In.ReadToEnd()); - modules.AddRange(newModules); - newModules.Clear(); - newModules.AddRange(dependencyFiles.Dependencies.Select(x => new Module(x))); - } while (newModules.Count > 0); + List missingDependencies = new(); + List references = new(); - Module[] allModules; - try + foreach (string dependency in module.RequiredDependencies) { - ModuleDependencyResolver dependencies = new(modules.ToArray()); - allModules = dependencies.GetDependencyOrder().ToArray(); + if (!Directory.Exists($"./cache/modules/{dependency}")) + { + missingDependencies.Add(dependency); + } + else + { + references.Add(MetadataReference.CreateFromFile($"./cache/modules/{dependency}/{dependency}.dll")); + } } - catch (Exception e) + + if (missingDependencies.Count > 0) { - Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, module.Name, module.Description, module.Version, module.RequiredDependencies, module.OptionalDependencies, $"Missing dependencies: {string.Join(", ", missingDependencies)}"))); return; } try { - module.Compile(); + module.Compile(references.ToArray()); + if (!Directory.Exists($"./cache/modules/{module.Name}")) + { + Directory.CreateDirectory($"./cache/modules/{module.Name}"); + } + File.WriteAllBytes($"./cache/modules/{module.Name}/{module.Name}.dll", module.AssemblyBytes); + + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(true, module.Name, module.Description, module.Version, module.RequiredDependencies, module.OptionalDependencies, null))); } catch (Exception e) { @@ -88,21 +76,8 @@ static void Main(string[] args) } -public enum ResponseType -{ - DependencyList, - VerificationResult -} - -public interface IResponse -{ - public ResponseType ResponseType { get; } -} - -internal class VerificationResponse : IResponse +internal class VerificationResponse { - public ResponseType ResponseType => ResponseType.VerificationResult; - public VerificationResponse(bool success, string name, string description, string version, string[] requiredDependencies, string[] optionalDependencies, string errors) { this.Success = success; @@ -121,11 +96,4 @@ public VerificationResponse(bool success, string name, string description, strin public string[]? RequiredDependencies { get; set; } public string[]? OptionalDependencies { get; set; } public string? Errors { get; set; } -} - -internal class DependencyListResponse : IResponse -{ - public ResponseType ResponseType => ResponseType.DependencyList; - - public string[] Dependencies { get; set; } } \ No newline at end of file diff --git a/BBRAPIModuleVerfication/Properties/launchSettings.json b/BBRAPIModuleVerfication/Properties/launchSettings.json index 756f479..391e35c 100644 --- a/BBRAPIModuleVerfication/Properties/launchSettings.json +++ b/BBRAPIModuleVerfication/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "BBRAPIModuleVerfication": { "commandName": "Project", - "commandLineArgs": "E:\\Create\\Development\\Software\\C#\\BattleBit\\BattleBitBaseModules\\ModeratorTools.cs" + "commandLineArgs": "E:\\Create\\Development\\Software\\C#\\BattleBit\\BattleBitBaseModules\\SpectateControl.cs" } } } \ No newline at end of file diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index ba0a7fb..dd5734b 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -1,4 +1,5 @@ -using BattleBitAPI.Common; +using BattleBitAPI; +using BattleBitAPI.Common; using BBRAPIModules; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -37,6 +38,7 @@ internal class Module public string ModuleFilePath { get; } public Assembly? ModuleAssembly { get; private set; } + internal static bool logToConsole = true; internal SyntaxTree syntaxTree; internal string code; @@ -59,10 +61,13 @@ public Module(string moduleFilePath) private void initialize() { - Console.Write("Parsing module from file "); - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine(Path.GetFileName(this.ModuleFilePath)); - Console.ResetColor(); + if (logToConsole) + { + Console.Write("Parsing module from file "); + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(Path.GetFileName(this.ModuleFilePath)); + Console.ResetColor(); + } this.code = File.ReadAllText(this.ModuleFilePath); this.syntaxTree = CSharpSyntaxTree.ParseText(code, null, this.ModuleFilePath, Encoding.UTF8); @@ -70,12 +75,15 @@ private void initialize() this.getDependencies(); this.getMetadata(); - Console.Write("Module "); - Console.ForegroundColor = ConsoleColor.White; - Console.Write(this.Name); - Console.ResetColor(); - Console.WriteLine($" has {this.RequiredDependencies.Length} required and {this.OptionalDependencies.Length} optional dependencies"); - Console.WriteLine(); + if (logToConsole) + { + Console.Write("Module "); + Console.ForegroundColor = ConsoleColor.White; + Console.Write(this.Name); + Console.ResetColor(); + Console.WriteLine($" has {this.RequiredDependencies.Length} required and {this.OptionalDependencies.Length} optional dependencies"); + Console.WriteLine(); + } } private void getMetadata() @@ -155,34 +163,56 @@ public void Load() modules.Add(this); } - public void Compile() + public void Compile(PortableExecutableReference[]? extraReferences = null) { if (this.AssemblyBytes is not null) { return; } - Console.Write("Compiling module "); - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine(this.Name); - Console.ResetColor(); + if (logToConsole) + { + Console.Write("Compiling module "); + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(this.Name); + Console.ResetColor(); + } + + List references = new() + { + MetadataReference.CreateFromFile(typeof(BattleBitModule).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Player<>).Assembly.Location), + }; + + foreach (string dll in Directory.GetFiles(Path.GetDirectoryName(typeof(object).Assembly.Location), "*.dll")) + { + if (!IsAssemblyValidReference(dll)) + { + continue; + } + + references.Add(MetadataReference.CreateFromFile(dll)); + } - List refs = new(AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location)).Select(a => MetadataReference.CreateFromFile(a.Location))); foreach (Module module in modules) { using (MemoryStream assemblyStream = new(module.AssemblyBytes)) { - refs.Add(MetadataReference.CreateFromStream(assemblyStream)); + references.Add(MetadataReference.CreateFromStream(assemblyStream)); } } - refs.Add(MetadataReference.CreateFromFile(typeof(DynamicAttribute).Assembly.Location)); - refs.Add(MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.Location)); + if (extraReferences is not null) + { + references.AddRange(extraReferences); + } + references.Add(MetadataReference.CreateFromFile(typeof(DynamicAttribute).Assembly.Location)); + references.Add(MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.Location)); CSharpCompilation compilation = CSharpCompilation.Create(this.Name) .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithOptimizationLevel(OptimizationLevel.Debug) .WithPlatform(Platform.AnyCpu)) - .WithReferences(refs) + .WithReferences(references) .AddSyntaxTrees(this.syntaxTree); using (MemoryStream assemblyStream = new()) @@ -207,5 +237,31 @@ public void Compile() this.PDBBytes = pdbStream.ToArray(); } } + + private static bool IsAssemblyValidReference(string assemblyPath) + { + try + { + string code = "class Program { static void Main() { } }"; + + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code); + CSharpCompilation compilation = CSharpCompilation.Create( + "TempAssembly", + syntaxTrees: new[] { syntaxTree }, + references: new[] { MetadataReference.CreateFromFile(assemblyPath), MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, + options: new CSharpCompilationOptions(OutputKind.ConsoleApplication)); + + using (var ms = new MemoryStream()) + { + EmitResult result = compilation.Emit(ms); + + return result.Success; + } + } + catch (Exception) + { + return false; + } + } } } From 524631985a359e7d66cccb275823201b177baa5e Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Tue, 29 Aug 2023 01:26:08 +0200 Subject: [PATCH 04/19] Verification process --- .../BBRAPIModuleVerfication.csproj | 15 +++ BBRAPIModuleVerfication/Program.cs | 107 ++++++++++++++++++ BBRAPIModules/ModuleAttribute.cs | 20 ++++ BattleBitAPIRunner.sln | 6 + BattleBitAPIRunner/Module.cs | 24 +++- 5 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj create mode 100644 BBRAPIModuleVerfication/Program.cs create mode 100644 BBRAPIModules/ModuleAttribute.cs diff --git a/BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj b/BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj new file mode 100644 index 0000000..af16098 --- /dev/null +++ b/BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs new file mode 100644 index 0000000..1ac2925 --- /dev/null +++ b/BBRAPIModuleVerfication/Program.cs @@ -0,0 +1,107 @@ +using BattleBitAPIRunner; +using Newtonsoft.Json; + +namespace BBRAPIModuleVerfication; + +internal class Program +{ + static void Main(string[] args) + { + if (args.Length != 1) + { + Console.WriteLine("Usage: BBRAPIModuleVerfication "); + return; + } + + string filePath = args[0]; + + Module module; + try + { + module = new Module(filePath); + } + catch (Exception e) + { + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + return; + } + + List modules = new(); + List newModules = new() { module }; + DependencyListResponse dependencyFiles; + do + { + Console.WriteLine(JsonConvert.SerializeObject(new DependencyListResponse() { Dependencies = newModules.SelectMany(m => m.RequiredDependencies).Distinct().ToArray() })); + dependencyFiles = JsonConvert.DeserializeObject(Console.In.ReadToEnd()); + modules.AddRange(newModules); + newModules.Clear(); + newModules.AddRange(dependencyFiles.Dependencies.Select(x => new Module(x))); + } while (newModules.Count > 0); + + ModuleDependencyResolver dependencies = new(modules.ToArray()); + try + { + + + } + catch (Exception e) + { + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + return; + } + + try + { + Module[] allModules = dependencies.GetDependencyOrder().ToArray(); + + module.Compile(); + } + catch (Exception e) + { + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, module.Name, module.Description, module.Version, module.RequiredDependencies, module.OptionalDependencies, e.Message))); + return; + } + } +} + +public enum ResponseType +{ + DependencyList, + VerificationResult +} + +public interface IResponse +{ + public ResponseType ResponseType { get; } +} + +internal class VerificationResponse : IResponse +{ + public ResponseType ResponseType => ResponseType.VerificationResult; + + public VerificationResponse(bool success, string name, string description, string version, string[] requiredDependencies, string[] optionalDependencies, string errors) + { + this.Success = success; + this.Name = name; + this.Description = description; + this.Version = version; + this.RequiredDependencies = requiredDependencies; + this.OptionalDependencies = optionalDependencies; + this.Errors = errors; + } + + public bool Success { get; set; } + public string? Name { get; set; } + public string? Description { get; set; } + public string? Version { get; set; } + public string[]? RequiredDependencies { get; set; } + public string[]? OptionalDependencies { get; set; } + public string? Errors { get; set; } +} + +internal class DependencyListResponse : IResponse +{ + public ResponseType ResponseType => ResponseType.DependencyList; + + public string[] Dependencies { get; set; } +} \ No newline at end of file diff --git a/BBRAPIModules/ModuleAttribute.cs b/BBRAPIModules/ModuleAttribute.cs new file mode 100644 index 0000000..b033a29 --- /dev/null +++ b/BBRAPIModules/ModuleAttribute.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BBRAPIModules; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class ModuleAttribute : Attribute +{ + public string Description { get; set; } + public string Version { get; set; } + + public ModuleAttribute(string description, string version) + { + this.Description = description; + this.Version = version; + } +} diff --git a/BattleBitAPIRunner.sln b/BattleBitAPIRunner.sln index 7bc842d..80b3ede 100644 --- a/BattleBitAPIRunner.sln +++ b/BattleBitAPIRunner.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BattleBitAPIRunner", "Battl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BBRAPIModules", "BBRAPIModules\BBRAPIModules.csproj", "{B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BBRAPIModuleVerfication", "BBRAPIModuleVerfication\BBRAPIModuleVerfication.csproj", "{2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}.Debug|Any CPU.Build.0 = Debug|Any CPU {B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}.Release|Any CPU.Build.0 = Release|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index 43ffaa0..859b990 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -1,4 +1,5 @@ -using BattleBitAPI; +using BattleBitAPI.Common; +using BattleBitAPI; using BBRAPIModules; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -14,6 +15,7 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Linq; +[assembly: InternalsVisibleTo("BBRAPIModuleVerfication")] namespace BattleBitAPIRunner { @@ -26,6 +28,8 @@ internal class Module public AssemblyLoadContext? Context { get; private set; } public Type? ModuleType { get; private set; } public string? Name { get; private set; } + public string? Description { get; private set; } + public string? Version { get; private set; } public string[]? RequiredDependencies { get; private set; } public string[]? OptionalDependencies { get; private set; } public byte[] AssemblyBytes { get; private set; } @@ -64,6 +68,7 @@ private void initialize() this.syntaxTree = CSharpSyntaxTree.ParseText(code, null, this.ModuleFilePath, Encoding.UTF8); this.Name = this.getName(); this.getDependencies(); + this.getMetadata(); Console.Write("Module "); Console.ForegroundColor = ConsoleColor.White; @@ -73,6 +78,23 @@ private void initialize() Console.WriteLine(); } + private void getMetadata() + { + IEnumerable attributeSyntaxes = syntaxTree.GetRoot().DescendantNodes().OfType(); + IEnumerable moduleAttributes = attributeSyntaxes.Where(x => x.Name.ToString() + "Attribute" == nameof(ModuleAttribute)); + if (moduleAttributes.Count() != 1) + { + throw new Exception("Module must have exactly one ModuleAttribute"); + } + + AttributeSyntax moduleAttribute = moduleAttributes.First(); + IEnumerable moduleAttributeArguments = moduleAttribute.ArgumentList?.Arguments ?? throw new Exception("ModuleAttribute must have arguments"); + AttributeArgumentSyntax descriptionArgument = moduleAttributeArguments.ElementAtOrDefault(0) ?? throw new Exception("ModuleAttribute must have a description argument"); + AttributeArgumentSyntax versionArgument = moduleAttributeArguments.ElementAtOrDefault(1) ?? throw new Exception("ModuleAttribute must have a version argument"); + this.Description = descriptionArgument.Expression.ToString().Trim('"'); + this.Version = versionArgument.Expression.ToString().Trim('"'); + } + private void getDependencies() { IEnumerable attributeSyntaxes = syntaxTree.GetRoot().DescendantNodes().OfType(); From f0e6e04dae87d7f553de0c27d50f27e7a2bfe02d Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Tue, 29 Aug 2023 11:38:40 +0200 Subject: [PATCH 05/19] this won't work --- BBRAPIModuleVerfication/Program.cs | 34 ++++++++++++++++--- .../Properties/launchSettings.json | 8 +++++ BattleBitAPIRunner/Module.cs | 4 +-- 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 BBRAPIModuleVerfication/Properties/launchSettings.json diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs index 1ac2925..db0b29c 100644 --- a/BBRAPIModuleVerfication/Program.cs +++ b/BBRAPIModuleVerfication/Program.cs @@ -1,10 +1,34 @@ using BattleBitAPIRunner; +using BBRAPIModules; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis; using Newtonsoft.Json; +using Microsoft.CodeAnalysis.CSharp; +using System.Text; namespace BBRAPIModuleVerfication; internal class Program { + static string readUntilEOT() + { + StringBuilder inputBuffer = new StringBuilder(); + int readByte; + + while ((readByte = Console.Read()) != -1) + { + if (readByte == 228)//4) + { + break; + } + + char character = (char)readByte; + inputBuffer.Append(character); + } + + return inputBuffer.ToString(); + } + static void Main(string[] args) { if (args.Length != 1) @@ -38,11 +62,11 @@ static void Main(string[] args) newModules.AddRange(dependencyFiles.Dependencies.Select(x => new Module(x))); } while (newModules.Count > 0); - ModuleDependencyResolver dependencies = new(modules.ToArray()); + Module[] allModules; try { - - + ModuleDependencyResolver dependencies = new(modules.ToArray()); + allModules = dependencies.GetDependencyOrder().ToArray(); } catch (Exception e) { @@ -52,8 +76,6 @@ static void Main(string[] args) try { - Module[] allModules = dependencies.GetDependencyOrder().ToArray(); - module.Compile(); } catch (Exception e) @@ -62,6 +84,8 @@ static void Main(string[] args) return; } } + + } public enum ResponseType diff --git a/BBRAPIModuleVerfication/Properties/launchSettings.json b/BBRAPIModuleVerfication/Properties/launchSettings.json new file mode 100644 index 0000000..756f479 --- /dev/null +++ b/BBRAPIModuleVerfication/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "BBRAPIModuleVerfication": { + "commandName": "Project", + "commandLineArgs": "E:\\Create\\Development\\Software\\C#\\BattleBit\\BattleBitBaseModules\\ModeratorTools.cs" + } + } +} \ No newline at end of file diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index 859b990..4b17323 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -37,8 +37,8 @@ internal class Module public string ModuleFilePath { get; } public Assembly? ModuleAssembly { get; private set; } - private SyntaxTree syntaxTree; - private string code; + internal SyntaxTree syntaxTree; + internal string code; public static void UnloadContext() { From 6da5be847698af827763e7ad8119d18ceabfaddc Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Tue, 29 Aug 2023 14:29:41 +0200 Subject: [PATCH 06/19] This works --- BBRAPIModuleVerfication/Program.cs | 86 ++++++------------- .../Properties/launchSettings.json | 2 +- BattleBitAPIRunner/Module.cs | 39 ++++++--- 3 files changed, 53 insertions(+), 74 deletions(-) diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs index db0b29c..f05a1a6 100644 --- a/BBRAPIModuleVerfication/Program.cs +++ b/BBRAPIModuleVerfication/Program.cs @@ -5,30 +5,12 @@ using Newtonsoft.Json; using Microsoft.CodeAnalysis.CSharp; using System.Text; +using System.Collections.ObjectModel; namespace BBRAPIModuleVerfication; internal class Program { - static string readUntilEOT() - { - StringBuilder inputBuffer = new StringBuilder(); - int readByte; - - while ((readByte = Console.Read()) != -1) - { - if (readByte == 228)//4) - { - break; - } - - char character = (char)readByte; - inputBuffer.Append(character); - } - - return inputBuffer.ToString(); - } - static void Main(string[] args) { if (args.Length != 1) @@ -39,6 +21,8 @@ static void Main(string[] args) string filePath = args[0]; + Module.logToConsole = false; + Module module; try { @@ -46,37 +30,41 @@ static void Main(string[] args) } catch (Exception e) { - Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, Path.GetFileNameWithoutExtension(filePath), null, null, null, null, e.Message))); return; } - List modules = new(); - List newModules = new() { module }; - DependencyListResponse dependencyFiles; - do - { - Console.WriteLine(JsonConvert.SerializeObject(new DependencyListResponse() { Dependencies = newModules.SelectMany(m => m.RequiredDependencies).Distinct().ToArray() })); - dependencyFiles = JsonConvert.DeserializeObject(Console.In.ReadToEnd()); - modules.AddRange(newModules); - newModules.Clear(); - newModules.AddRange(dependencyFiles.Dependencies.Select(x => new Module(x))); - } while (newModules.Count > 0); + List missingDependencies = new(); + List references = new(); - Module[] allModules; - try + foreach (string dependency in module.RequiredDependencies) { - ModuleDependencyResolver dependencies = new(modules.ToArray()); - allModules = dependencies.GetDependencyOrder().ToArray(); + if (!Directory.Exists($"./cache/modules/{dependency}")) + { + missingDependencies.Add(dependency); + } + else + { + references.Add(MetadataReference.CreateFromFile($"./cache/modules/{dependency}/{dependency}.dll")); + } } - catch (Exception e) + + if (missingDependencies.Count > 0) { - Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, null, null, null, null, null, e.Message))); + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(false, module.Name, module.Description, module.Version, module.RequiredDependencies, module.OptionalDependencies, $"Missing dependencies: {string.Join(", ", missingDependencies)}"))); return; } try { - module.Compile(); + module.Compile(references.ToArray()); + if (!Directory.Exists($"./cache/modules/{module.Name}")) + { + Directory.CreateDirectory($"./cache/modules/{module.Name}"); + } + File.WriteAllBytes($"./cache/modules/{module.Name}/{module.Name}.dll", module.AssemblyBytes); + + Console.WriteLine(JsonConvert.SerializeObject(new VerificationResponse(true, module.Name, module.Description, module.Version, module.RequiredDependencies, module.OptionalDependencies, null))); } catch (Exception e) { @@ -88,21 +76,8 @@ static void Main(string[] args) } -public enum ResponseType -{ - DependencyList, - VerificationResult -} - -public interface IResponse -{ - public ResponseType ResponseType { get; } -} - -internal class VerificationResponse : IResponse +internal class VerificationResponse { - public ResponseType ResponseType => ResponseType.VerificationResult; - public VerificationResponse(bool success, string name, string description, string version, string[] requiredDependencies, string[] optionalDependencies, string errors) { this.Success = success; @@ -121,11 +96,4 @@ public VerificationResponse(bool success, string name, string description, strin public string[]? RequiredDependencies { get; set; } public string[]? OptionalDependencies { get; set; } public string? Errors { get; set; } -} - -internal class DependencyListResponse : IResponse -{ - public ResponseType ResponseType => ResponseType.DependencyList; - - public string[] Dependencies { get; set; } } \ No newline at end of file diff --git a/BBRAPIModuleVerfication/Properties/launchSettings.json b/BBRAPIModuleVerfication/Properties/launchSettings.json index 756f479..391e35c 100644 --- a/BBRAPIModuleVerfication/Properties/launchSettings.json +++ b/BBRAPIModuleVerfication/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "BBRAPIModuleVerfication": { "commandName": "Project", - "commandLineArgs": "E:\\Create\\Development\\Software\\C#\\BattleBit\\BattleBitBaseModules\\ModeratorTools.cs" + "commandLineArgs": "E:\\Create\\Development\\Software\\C#\\BattleBit\\BattleBitBaseModules\\SpectateControl.cs" } } } \ No newline at end of file diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index 4b17323..fba25f8 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -37,6 +37,7 @@ internal class Module public string ModuleFilePath { get; } public Assembly? ModuleAssembly { get; private set; } + internal static bool logToConsole = true; internal SyntaxTree syntaxTree; internal string code; @@ -59,10 +60,13 @@ public Module(string moduleFilePath) private void initialize() { - Console.Write("Parsing module from file "); - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine(Path.GetFileName(this.ModuleFilePath)); - Console.ResetColor(); + if (logToConsole) + { + Console.Write("Parsing module from file "); + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(Path.GetFileName(this.ModuleFilePath)); + Console.ResetColor(); + } this.code = File.ReadAllText(this.ModuleFilePath); this.syntaxTree = CSharpSyntaxTree.ParseText(code, null, this.ModuleFilePath, Encoding.UTF8); @@ -70,12 +74,15 @@ private void initialize() this.getDependencies(); this.getMetadata(); - Console.Write("Module "); - Console.ForegroundColor = ConsoleColor.White; - Console.Write(this.Name); - Console.ResetColor(); - Console.WriteLine($" has {this.RequiredDependencies.Length} required and {this.OptionalDependencies.Length} optional dependencies"); - Console.WriteLine(); + if (logToConsole) + { + Console.Write("Module "); + Console.ForegroundColor = ConsoleColor.White; + Console.Write(this.Name); + Console.ResetColor(); + Console.WriteLine($" has {this.RequiredDependencies.Length} required and {this.OptionalDependencies.Length} optional dependencies"); + Console.WriteLine(); + } } private void getMetadata() @@ -162,10 +169,14 @@ public void Compile(PortableExecutableReference[]? extraReferences = null) return; } - Console.Write("Compiling module "); - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine(this.Name); - Console.ResetColor(); + if (logToConsole) + { + Console.Write("Compiling module "); + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(this.Name); + Console.ResetColor(); + } + List references = new() { MetadataReference.CreateFromFile(typeof(BattleBitModule).Assembly.Location), From 93dd8f241176437cdce7ec6b31f8cecd1de153b6 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Tue, 29 Aug 2023 01:26:08 +0200 Subject: [PATCH 07/19] Verification process --- BBRAPIModuleVerfication/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs index f05a1a6..a254b36 100644 --- a/BBRAPIModuleVerfication/Program.cs +++ b/BBRAPIModuleVerfication/Program.cs @@ -1,4 +1,4 @@ -using BattleBitAPIRunner; +using BattleBitAPIRunner; using BBRAPIModules; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis; From 3db28300efb4ee438bc3ed3c2b3c97ee19689841 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sat, 9 Sep 2023 11:17:12 +0200 Subject: [PATCH 08/19] Version bump --- BattleBitAPIRunner/BattleBitAPIRunner.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BattleBitAPIRunner/BattleBitAPIRunner.csproj b/BattleBitAPIRunner/BattleBitAPIRunner.csproj index adfb4cc..310704b 100644 --- a/BattleBitAPIRunner/BattleBitAPIRunner.csproj +++ b/BattleBitAPIRunner/BattleBitAPIRunner.csproj @@ -5,7 +5,7 @@ net6.0 enable enable - 0.4.12.6 + 0.4.12.7 $(AssemblyVersion) From e964bf4730c77bcb06bdffb0f77efab8af40df03 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sat, 9 Sep 2023 11:17:49 +0200 Subject: [PATCH 09/19] Random guess on modules loading without config but with config --- BattleBitAPIRunner/Program.cs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/BattleBitAPIRunner/Program.cs b/BattleBitAPIRunner/Program.cs index ecc0737..e1172ab 100644 --- a/BattleBitAPIRunner/Program.cs +++ b/BattleBitAPIRunner/Program.cs @@ -453,6 +453,8 @@ private void loadServerModules(RunnerServer server, IPAddress? ip = null, ushort } } + battleBitModules = battleBitModules.Where(m => m.Server is not null).ToList(); + foreach (BattleBitModule battleBitModule in battleBitModules) { // Resolve references @@ -540,22 +542,11 @@ private void ModuleConfiguration_OnLoadingRequest(object? sender, BattleBitModul // Create instance of type of the property if it doesn't exist ModuleConfiguration? configurationValue = property.GetValue(module) as ModuleConfiguration; - if (configurationValue is null) - { - configurationValue = Activator.CreateInstance(property.PropertyType) as ModuleConfiguration; - configurationValue!.Initialize(module, property, serverName); - configurationValue.OnLoadingRequest += ModuleConfiguration_OnLoadingRequest; - configurationValue.OnSavingRequest += ModuleConfiguration_OnSavingRequest; - - if (!File.Exists(filePath)) - { - File.WriteAllText(filePath, JsonConvert.SerializeObject(configurationValue, Formatting.Indented)); - } - } if (File.Exists(filePath)) { configurationValue = JsonConvert.DeserializeObject(File.ReadAllText(filePath), property.PropertyType) as ModuleConfiguration; + if (configurationValue is null) { Console.ForegroundColor = ConsoleColor.Red; @@ -565,11 +556,22 @@ private void ModuleConfiguration_OnLoadingRequest(object? sender, BattleBitModul module.Unload(); return; } - configurationValue.Initialize(module, property, serverName); - configurationValue.OnLoadingRequest += ModuleConfiguration_OnLoadingRequest; - configurationValue.OnSavingRequest += ModuleConfiguration_OnSavingRequest; - property.SetValue(module, configurationValue); } + + if (configurationValue is null) + { + configurationValue = Activator.CreateInstance(property.PropertyType) as ModuleConfiguration; + + if (!File.Exists(filePath)) + { + File.WriteAllText(filePath, JsonConvert.SerializeObject(configurationValue, Formatting.Indented)); + } + } + + configurationValue!.Initialize(module, property, serverName); + configurationValue.OnLoadingRequest += ModuleConfiguration_OnLoadingRequest; + configurationValue.OnSavingRequest += ModuleConfiguration_OnSavingRequest; + property.SetValue(module, configurationValue); } private void startServerListener() From 18d344d5fe6ebb88a6fc6193b3bec3870c6be543 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 10 Sep 2023 11:44:12 +0200 Subject: [PATCH 10/19] Removes Call implementation of optional references --- BBRAPIModules/BattleBitModule.cs | 39 +------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/BBRAPIModules/BattleBitModule.cs b/BBRAPIModules/BattleBitModule.cs index 9444326..e819733 100644 --- a/BBRAPIModules/BattleBitModule.cs +++ b/BBRAPIModules/BattleBitModule.cs @@ -1,7 +1,5 @@ -using BattleBitAPI; -using BattleBitAPI.Common; +using BattleBitAPI.Common; using BattleBitAPI.Server; -using System.Reflection; using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("BattleBitAPIRunner")] @@ -19,41 +17,6 @@ internal void SetServer(RunnerServer server) this.Server = server; } - public void Call(string methodName, params object?[]? parameters) - { - this.Call(methodName, parameters); - } - - public T Call(string methodName, params object?[]? parameters) - { - var method = this.GetType().GetMethod(methodName); - if (method == null) - { - return default(T); - } - - ParameterInfo[] methodParameters = method.GetParameters(); - - List fullParameters = new(parameters ?? new object?[] { }); - - if (methodParameters.Length > 0 && methodParameters.Length != parameters?.Length) - { - for (int i = parameters?.Length ?? 0; i < methodParameters.Length; i++) - { - if (methodParameters[i].IsOptional || methodParameters[i].HasDefaultValue) - { - fullParameters.Add(methodParameters[i].DefaultValue); - } - else - { - throw new ArgumentException($"Parameter {methodParameters[i].Name} is not optional and does not have a default value."); - } - } - } - - return (T)method.Invoke(this, fullParameters.ToArray()); - } - public void Unload() { this.IsLoaded = false; From 3e5e6b074920ec79bd68a1f608913795f8a6f909 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 10 Sep 2023 11:50:10 +0200 Subject: [PATCH 11/19] Adds console command callback --- BBRAPIModules/BattleBitModule.cs | 1 + BBRAPIModules/RunnerServer.cs | 3 ++- BattleBitAPIRunner/Program.cs | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/BBRAPIModules/BattleBitModule.cs b/BBRAPIModules/BattleBitModule.cs index e819733..81e0684 100644 --- a/BBRAPIModules/BattleBitModule.cs +++ b/BBRAPIModules/BattleBitModule.cs @@ -26,6 +26,7 @@ public void Unload() public virtual void OnModulesLoaded() { } // sighs silently public virtual void OnModuleUnloading() { } + public virtual void OnConsoleCommand(string command) { } #region GameServer.cs copy-paste // TODO: there must be a better way to do this!? diff --git a/BBRAPIModules/RunnerServer.cs b/BBRAPIModules/RunnerServer.cs index 2ebdc5f..cef8442 100644 --- a/BBRAPIModules/RunnerServer.cs +++ b/BBRAPIModules/RunnerServer.cs @@ -1,6 +1,7 @@ using BattleBitAPI.Common; using BattleBitAPI.Server; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace BBRAPIModules { @@ -114,7 +115,7 @@ private async Task invokeOnModulesWithBoolReturnValue(string method, param return result; } - private async Task invokeOnModules(string method, params object?[] parameters) + internal async Task invokeOnModules(string method, params object?[] parameters) { Stopwatch stopwatch = new(); foreach (BattleBitModule module in this.modules) diff --git a/BattleBitAPIRunner/Program.cs b/BattleBitAPIRunner/Program.cs index e1172ab..c8cacfd 100644 --- a/BattleBitAPIRunner/Program.cs +++ b/BattleBitAPIRunner/Program.cs @@ -182,6 +182,11 @@ private void consoleCommandHandler() continue; } + foreach (RunnerServer commandServer in this.servers) + { + commandServer.invokeOnModules(nameof(BattleBitModule.OnConsoleCommand), command).Wait(); + } + switch (commandParts[0]) { case "servers": @@ -546,7 +551,7 @@ private void ModuleConfiguration_OnLoadingRequest(object? sender, BattleBitModul if (File.Exists(filePath)) { configurationValue = JsonConvert.DeserializeObject(File.ReadAllText(filePath), property.PropertyType) as ModuleConfiguration; - + if (configurationValue is null) { Console.ForegroundColor = ConsoleColor.Red; From bcbf2d8b9b8f7fee9a1dbf29dd8d7d4c2ea669f3 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 10 Sep 2023 11:52:24 +0200 Subject: [PATCH 12/19] Version bump --- BBRAPIModules/BBRAPIModules.csproj | 2 +- BattleBitAPIRunner/BattleBitAPIRunner.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BBRAPIModules/BBRAPIModules.csproj b/BBRAPIModules/BBRAPIModules.csproj index 07c3b0d..ff30b00 100644 --- a/BBRAPIModules/BBRAPIModules.csproj +++ b/BBRAPIModules/BBRAPIModules.csproj @@ -6,7 +6,7 @@ enable True BattleBit Remastered Modular Community Server API - 0.4.11 + 0.4.13 $(AssemblyVersion) $(AssemblyVersion) RainOrigami diff --git a/BattleBitAPIRunner/BattleBitAPIRunner.csproj b/BattleBitAPIRunner/BattleBitAPIRunner.csproj index 310704b..64e27f6 100644 --- a/BattleBitAPIRunner/BattleBitAPIRunner.csproj +++ b/BattleBitAPIRunner/BattleBitAPIRunner.csproj @@ -5,7 +5,7 @@ net6.0 enable enable - 0.4.12.7 + 0.4.13 $(AssemblyVersion) From 5374d8f6f42b0c59a0a6847a92b839c9e801af76 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 10 Sep 2023 12:28:17 +0200 Subject: [PATCH 13/19] Merge issue --- BattleBitAPIRunner/Module.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index 9af4291..156ee43 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -133,7 +133,7 @@ private void initialize() Console.ForegroundColor = ConsoleColor.White; Console.Write(this.Name); Console.ResetColor(); - Console.WriteLine($" has {this.RequiredDepe ndencies.Length} required and {this.OptionalDependencies.Length} optional dependencies"); + Console.WriteLine($" has {this.RequiredDependencies.Length} required and {this.OptionalDependencies.Length} optional dependencies"); Console.WriteLine(); } } From 37f4cdd3d66457b6b006fc12ac042a399fb64db6 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Mon, 18 Sep 2023 12:13:58 +0200 Subject: [PATCH 14/19] Build artifacts --- .github/workflows/build-artifacts.yaml | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/build-artifacts.yaml diff --git a/.github/workflows/build-artifacts.yaml b/.github/workflows/build-artifacts.yaml new file mode 100644 index 0000000..6aa1113 --- /dev/null +++ b/.github/workflows/build-artifacts.yaml @@ -0,0 +1,48 @@ +name: Build Artifacts + +permissions: + contents: write + +on: + push: + branches: + - '*' + +jobs: + build-artifacts: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v3.0.3 + with: + dotnet-version: 6 + + - name: NuGet Restore + run: dotnet restore + + - name: Build and Publish project + run: dotnet publish BattleBitAPIRunner/BattleBitAPIRunner.csproj -c Release -o ./publish --self-contained false --framework net6.0 --runtime win-x64 + + - name: Build nuget + run: dotnet build BattleBitAPIRunner/BattleBitAPIRunner.csproj -c Release + + - name: Create NuGet package + run: dotnet pack BBRAPIModules/BBRAPIModules.csproj --configuration Release --output ./nuget + + - name: Upload NuGet package artifact + uses: actions/upload-artifact@v2 + with: + name: NuGet Package + path: ./nuget/*.nupkg + + - name: Upload Release artifact + uses: actions/upload-artifact@v2 + with: + name: BattleBitAPIRunner-beta + path: ./publish/* \ No newline at end of file From c8b5b90e5e877abcd627e81916f83d96f9c1781e Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Wed, 20 Sep 2023 09:33:46 +0200 Subject: [PATCH 15/19] Fix typo --- ...duleVerfication.csproj => BBRAPIModuleVerification.csproj} | 0 BBRAPIModuleVerfication/Program.cs | 4 ++-- BBRAPIModuleVerfication/Properties/launchSettings.json | 2 +- BattleBitAPIRunner.sln | 2 +- BattleBitAPIRunner/Module.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename BBRAPIModuleVerfication/{BBRAPIModuleVerfication.csproj => BBRAPIModuleVerification.csproj} (100%) diff --git a/BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj b/BBRAPIModuleVerfication/BBRAPIModuleVerification.csproj similarity index 100% rename from BBRAPIModuleVerfication/BBRAPIModuleVerfication.csproj rename to BBRAPIModuleVerfication/BBRAPIModuleVerification.csproj diff --git a/BBRAPIModuleVerfication/Program.cs b/BBRAPIModuleVerfication/Program.cs index a254b36..cc1e105 100644 --- a/BBRAPIModuleVerfication/Program.cs +++ b/BBRAPIModuleVerfication/Program.cs @@ -7,7 +7,7 @@ using System.Text; using System.Collections.ObjectModel; -namespace BBRAPIModuleVerfication; +namespace BBRAPIModuleVerification; internal class Program { @@ -15,7 +15,7 @@ static void Main(string[] args) { if (args.Length != 1) { - Console.WriteLine("Usage: BBRAPIModuleVerfication "); + Console.WriteLine("Usage: BBRAPIModuleVerification "); return; } diff --git a/BBRAPIModuleVerfication/Properties/launchSettings.json b/BBRAPIModuleVerfication/Properties/launchSettings.json index 391e35c..2f09f78 100644 --- a/BBRAPIModuleVerfication/Properties/launchSettings.json +++ b/BBRAPIModuleVerfication/Properties/launchSettings.json @@ -1,6 +1,6 @@ { "profiles": { - "BBRAPIModuleVerfication": { + "BBRAPIModuleVerification": { "commandName": "Project", "commandLineArgs": "E:\\Create\\Development\\Software\\C#\\BattleBit\\BattleBitBaseModules\\SpectateControl.cs" } diff --git a/BattleBitAPIRunner.sln b/BattleBitAPIRunner.sln index 80b3ede..16ee168 100644 --- a/BattleBitAPIRunner.sln +++ b/BattleBitAPIRunner.sln @@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BattleBitAPIRunner", "Battl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BBRAPIModules", "BBRAPIModules\BBRAPIModules.csproj", "{B17890B8-4D8C-4FA7-BFFB-20679A42AF7B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BBRAPIModuleVerfication", "BBRAPIModuleVerfication\BBRAPIModuleVerfication.csproj", "{2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BBRAPIModuleVerification", "BBRAPIModuleVerfication\BBRAPIModuleVerification.csproj", "{2A5EC0BE-9755-4383-A4B6-A3D2275DA9A7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index 156ee43..f55a939 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -15,7 +15,7 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Linq; -[assembly: InternalsVisibleTo("BBRAPIModuleVerfication")] +[assembly: InternalsVisibleTo("BBRAPIModuleVerification")] namespace BattleBitAPIRunner { From ef5e3eab5679e8efbc929ab0ded370dac6141878 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 24 Sep 2023 15:05:54 +0200 Subject: [PATCH 16/19] Fixes slow module loading --- BattleBitAPIRunner/Module.cs | 50 ++++++++++++------------------------ 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index f55a939..57662a4 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -15,6 +15,8 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Linq; +using BattleBitAPI.Server; + [assembly: InternalsVisibleTo("BBRAPIModuleVerification")] namespace BattleBitAPIRunner @@ -43,51 +45,47 @@ internal class Module public static void LoadContext(string[] dependencies) { - if (baseReferences is null) - { - loadReferences(dependencies); - } - loadDepedencies(dependencies); } - private static void loadReferences(string[] dependencies) + + private static void loadDepedencies(string[] dependencies) { List references = new() { MetadataReference.CreateFromFile(typeof(BattleBitModule).Assembly.Location), MetadataReference.CreateFromFile(typeof(Player<>).Assembly.Location), + MetadataReference.CreateFromFile(typeof(RunnerServer).Assembly.Location), + MetadataReference.CreateFromFile(typeof(GameServer<>).Assembly.Location), }; foreach (string dll in Directory.GetFiles(Path.GetDirectoryName(typeof(object).Assembly.Location)!, "*.dll")) { - if (!IsAssemblyValidReference(dll)) { continue; } references.Add(MetadataReference.CreateFromFile(dll)); + try + { + moduleContext.LoadFromAssemblyPath(Path.GetFullPath(dll)); + } + catch + { + } } foreach (string dependency in dependencies) { - + moduleContext.LoadFromAssemblyPath(Path.GetFullPath(dependency)); references.Add(MetadataReference.CreateFromFile(Path.GetFullPath(dependency))); } baseReferences = references.ToArray(); } - private static void loadDepedencies(string[] dependencies) - { - foreach (string dependency in dependencies) - { - moduleContext.LoadFromAssemblyPath(Path.GetFullPath(dependency)); - } - } - public static void UnloadContext() { moduleContext.Unload(); @@ -123,7 +121,7 @@ private void initialize() { throw new Exception($"Module {Path.GetFileName(this.ModuleFilePath)} does not have the same name as the class {this.Name} that inherits from {nameof(BattleBitModule)}"); } - + this.getDependencies(); this.getMetadata(); @@ -215,7 +213,7 @@ public void Load() modules.Add(this); } - public static PortableExecutableReference[]? baseReferences = null; + public static PortableExecutableReference[] baseReferences = null!; public void Compile(PortableExecutableReference[]? extraReferences = null) { @@ -232,21 +230,7 @@ public void Compile(PortableExecutableReference[]? extraReferences = null) Console.ResetColor(); } - List references = new() - { - MetadataReference.CreateFromFile(typeof(BattleBitModule).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Player<>).Assembly.Location), - }; - - foreach (string dll in Directory.GetFiles(Path.GetDirectoryName(typeof(object).Assembly.Location), "*.dll")) - { - if (!IsAssemblyValidReference(dll)) - { - continue; - } - - references.Add(MetadataReference.CreateFromFile(dll)); - } + List references = new(baseReferences); foreach (Module module in modules) { From ecedb19aef3d1254040853519caa7621f1ca10a0 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 24 Sep 2023 15:06:12 +0200 Subject: [PATCH 17/19] Fixes config default values not being overwritten --- BattleBitAPIRunner/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BattleBitAPIRunner/Program.cs b/BattleBitAPIRunner/Program.cs index c8cacfd..d744efd 100644 --- a/BattleBitAPIRunner/Program.cs +++ b/BattleBitAPIRunner/Program.cs @@ -550,7 +550,7 @@ private void ModuleConfiguration_OnLoadingRequest(object? sender, BattleBitModul if (File.Exists(filePath)) { - configurationValue = JsonConvert.DeserializeObject(File.ReadAllText(filePath), property.PropertyType) as ModuleConfiguration; + configurationValue = JsonConvert.DeserializeObject(File.ReadAllText(filePath), property.PropertyType, new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace }) as ModuleConfiguration; if (configurationValue is null) { From bbba5709db63602b52f851dcf32cc9c47ec5456f Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 24 Sep 2023 15:06:28 +0200 Subject: [PATCH 18/19] Fixes console command invocation --- BattleBitAPIRunner/Program.cs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/BattleBitAPIRunner/Program.cs b/BattleBitAPIRunner/Program.cs index d744efd..c7af270 100644 --- a/BattleBitAPIRunner/Program.cs +++ b/BattleBitAPIRunner/Program.cs @@ -182,9 +182,25 @@ private void consoleCommandHandler() continue; } - foreach (RunnerServer commandServer in this.servers) + foreach (RunnerServer server in this.servers) { - commandServer.invokeOnModules(nameof(BattleBitModule.OnConsoleCommand), command).Wait(); + List instances = new(); + foreach (Module module in Module.Modules) + { + BattleBitModule? moduleInstance = server.GetModule(module.ModuleType!); + if (moduleInstance is null) + { + continue; + } + + instances.Add(moduleInstance); + moduleInstance.OnConsoleCommand(command); + } + + foreach (BattleBitModule moduleInstance in instances) + { + moduleInstance.Unload(); + } } switch (commandParts[0]) From 1b043a0a7be7a0eb22cc1a26131b835ad6c6a4b7 Mon Sep 17 00:00:00 2001 From: RainOrigami Date: Sun, 24 Sep 2023 15:28:03 +0200 Subject: [PATCH 19/19] Some kind of magic --- BattleBitAPIRunner/Module.cs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/BattleBitAPIRunner/Module.cs b/BattleBitAPIRunner/Module.cs index 57662a4..4da62f2 100644 --- a/BattleBitAPIRunner/Module.cs +++ b/BattleBitAPIRunner/Module.cs @@ -45,47 +45,53 @@ internal class Module public static void LoadContext(string[] dependencies) { + if (baseReferences is null) + { + loadReferences(dependencies); + } + loadDepedencies(dependencies); } - private static void loadDepedencies(string[] dependencies) + + private static void loadReferences(string[] dependencies) { List references = new() { MetadataReference.CreateFromFile(typeof(BattleBitModule).Assembly.Location), MetadataReference.CreateFromFile(typeof(Player<>).Assembly.Location), - MetadataReference.CreateFromFile(typeof(RunnerServer).Assembly.Location), - MetadataReference.CreateFromFile(typeof(GameServer<>).Assembly.Location), }; foreach (string dll in Directory.GetFiles(Path.GetDirectoryName(typeof(object).Assembly.Location)!, "*.dll")) { + if (!IsAssemblyValidReference(dll)) { continue; } references.Add(MetadataReference.CreateFromFile(dll)); - try - { - moduleContext.LoadFromAssemblyPath(Path.GetFullPath(dll)); - } - catch - { - } } foreach (string dependency in dependencies) { - moduleContext.LoadFromAssemblyPath(Path.GetFullPath(dependency)); + references.Add(MetadataReference.CreateFromFile(Path.GetFullPath(dependency))); } baseReferences = references.ToArray(); } + private static void loadDepedencies(string[] dependencies) + { + foreach (string dependency in dependencies) + { + moduleContext.LoadFromAssemblyPath(Path.GetFullPath(dependency)); + } + } + public static void UnloadContext() { moduleContext.Unload();