diff --git a/MaaFramework.Binding.sln b/MaaFramework.Binding.sln index 3a50aff..3c4b511 100644 --- a/MaaFramework.Binding.sln +++ b/MaaFramework.Binding.sln @@ -8,8 +8,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig .gitattributes = .gitattributes .gitignore = .gitignore - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props + src\Directory.Build.props = src\Directory.Build.props + src\Directory.Packages.props = src\Directory.Packages.props LICENSE.md = LICENSE.md README.md = README.md README.zh_cn.md = README.zh_cn.md diff --git a/sample/Agent/.config/dotnet-tools.json b/sample/Agent/.config/dotnet-tools.json new file mode 100644 index 0000000..fb26112 --- /dev/null +++ b/sample/Agent/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-script": { + "version": "1.6.0", + "commands": [ + "dotnet-script" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/sample/Agent/AgentChild.cs b/sample/Agent/AgentChild.cs new file mode 100644 index 0000000..1586026 --- /dev/null +++ b/sample/Agent/AgentChild.cs @@ -0,0 +1,58 @@ +#!/usr/bin/env dotnet-script +#r "nuget: Maa.Framework.Binding.Native, 4.0.0-preview.25163.6" + +using MaaFramework.Binding; +using MaaFramework.Binding.Buffers; +using MaaFramework.Binding.Custom; + +var commandLineArgs = Environment.GetCommandLineArgs(); +if (commandLineArgs.Length < 4) +{ + Console.WriteLine("Call AgentMain.cs instead of this file."); + return 1; +} + +var socketId = commandLineArgs[^1]; +var userPath = commandLineArgs[^2]; +var dllPath = commandLineArgs[^3]; + +NativeBindingInfo.Set(isAgentServer: true, dllPath); // First step +_ = new MaaToolkit(true, userPath); +var agentServer = new MaaAgentServer(); +agentServer.Register(new MyRec()); +agentServer.Register(new MyAct()); +agentServer.StartUp(socketId); +agentServer.Join(); +agentServer.ShutDown(); + +Console.Write("Press any key to exit:"); +Console.ReadKey(); +return 0; + +internal sealed class MyRec : IMaaCustomRecognition +{ + public string Name { get; set; } = nameof(MyRec); + + public bool Analyze(in IMaaContext context, in AnalyzeArgs args, in AnalyzeResults results) + { + Console.WriteLine("{0} Called", Name); + + results.Box.SetValues(0, 0, 100, 100); + results.Detail.SetValue("Hello Client!"); + return true; + } +} + +internal sealed class MyAct : IMaaCustomAction +{ + public string Name { get; set; } = nameof(MyAct); + + public bool Run(in IMaaContext context, in RunArgs args) + { + Console.WriteLine("{0} Called", Name); + Console.WriteLine("recognition detail: {0}", args.RecognitionDetail); + Console.WriteLine("custom action param: {0}", args.ActionParam); + + return true; + } +} diff --git a/sample/Agent/AgentMain.cs b/sample/Agent/AgentMain.cs new file mode 100644 index 0000000..fce0db6 --- /dev/null +++ b/sample/Agent/AgentMain.cs @@ -0,0 +1,68 @@ +#!/usr/bin/env dotnet-script +#r "nuget: Maa.Framework.Native, 4.0.0-preview.25163.6" +#r "nuget: Maa.Framework.Runtime.win-x64, 4.0.0" + +using System.Diagnostics; +using MaaFramework.Binding; + +var toolkit = new MaaToolkit(true); +var resource = new MaaResource(); +var maa = new MaaTasker +{ + Controller = toolkit.AdbDevice.Find().First().ToAdbController(), + Resource = resource, + DisposeOptions = DisposeOptions.All, + Toolkit = toolkit, +}; + +if (!maa.Initialized) + throw new InvalidOperationException("Failed to init tasker."); + +var agent = new MaaAgentClient +{ + Resource = resource, + DisposeOptions = DisposeOptions.All, +}; + +var socketId = agent.CreateSocket(string.Empty) + ?? throw new InvalidOperationException("Failed to create socket."); + +var p = Process.Start(new ProcessStartInfo( + "dotnet",["script", + "AgentChild.cs", + NativeBindingInfo.NativeAssemblyDirectory + ?? throw new ArgumentNullException("Native.BindingInfo.NativeAssemblyDirectory"), + Environment.CurrentDirectory, + socketId]) { UseShellExecute = true }); + +if (!agent.LinkStart()) + throw new InvalidOperationException("Failed to connect."); + +var ppover = """ +{ + "Entry": {"next": "Rec"}, + "Rec": { + "recognition": "Custom", + "custom_recognition": "MyRec", + "action": "Custom", + "custom_action": "MyAct", + "custom_action_param": { + "param": "Hello Server!" + } + } +} +"""; +Console.WriteLine(ppover); + +var detail = maa + .AppendTask("Entry", ppover) + .WaitFor(MaaJobStatus.Succeeded) + .QueryTaskDetail() + ?? throw new InvalidOperationException("Failed to pipeline."); +Console.WriteLine($"pipeline detail: {detail}"); +Console.WriteLine($"MyRec detail: {detail.QueryRecognitionDetail(maa, 1)?.Detail}"); + +agent.LinkStop(); + +Console.Write("Press any key to exit:"); +Console.ReadKey(); diff --git a/sample/Agent/QuickStart.ps1 b/sample/Agent/QuickStart.ps1 new file mode 100644 index 0000000..f5988bd --- /dev/null +++ b/sample/Agent/QuickStart.ps1 @@ -0,0 +1,3 @@ +$ENV:DOTNET_SCRIPT_CACHE_LOCATION="$PSScriptRoot\.cache" +dotnet tool restore +dotnet script AgentMain.cs -s https://api.nuget.org/v3/index.json -s https://maaxyz.github.io/pkg/nuget/index.json \ No newline at end of file diff --git a/Directory.Build.props b/src/Directory.Build.props similarity index 100% rename from Directory.Build.props rename to src/Directory.Build.props diff --git a/Directory.Packages.props b/src/Directory.Packages.props similarity index 81% rename from Directory.Packages.props rename to src/Directory.Packages.props index 4d30807..1c088bd 100644 --- a/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -4,8 +4,8 @@ true - - + + diff --git a/src/MaaFramework.Binding.Native/Interop/AgentClient/MaaAgentClient.cs b/src/MaaFramework.Binding.Native/Interop/AgentClient/MaaAgentClient.cs new file mode 100644 index 0000000..fbb2b60 --- /dev/null +++ b/src/MaaFramework.Binding.Native/Interop/AgentClient/MaaAgentClient.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记 +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace MaaFramework.Binding.Interop.Native; + +public static partial class MaaAgentClient +{ + [LibraryImport("MaaAgentClient", StringMarshalling = StringMarshalling.Utf8)] + public static partial MaaAgentClientHandle MaaAgentClientCreate(); + + [LibraryImport("MaaAgentClient", StringMarshalling = StringMarshalling.Utf8)] + public static partial void MaaAgentClientDestroy(MaaAgentClientHandle client); + + [LibraryImport("MaaAgentClient", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool MaaAgentClientBindResource(MaaAgentClientHandle client, MaaResourceHandle res); + + [LibraryImport("MaaAgentClient", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool MaaAgentClientCreateSocket(MaaAgentClientHandle client, MaaStringBufferHandle identifier); + + [LibraryImport("MaaAgentClient", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool MaaAgentClientConnect(MaaAgentClientHandle client); + + [LibraryImport("MaaAgentClient", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool MaaAgentClientDisconnect(MaaAgentClientHandle client); +} diff --git a/src/MaaFramework.Binding.Native/Interop/AgentClient/MaaAgentClientDef.cs b/src/MaaFramework.Binding.Native/Interop/AgentClient/MaaAgentClientDef.cs new file mode 100644 index 0000000..ac2ae0c --- /dev/null +++ b/src/MaaFramework.Binding.Native/Interop/AgentClient/MaaAgentClientDef.cs @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记 +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 + +global using MaaAgentClientHandle = nint; + +namespace MaaFramework.Binding.Interop.Native; + diff --git a/src/MaaFramework.Binding.Native/Interop/AgentServer/MaaAgentServer.cs b/src/MaaFramework.Binding.Native/Interop/AgentServer/MaaAgentServer.cs new file mode 100644 index 0000000..e0cf4c8 --- /dev/null +++ b/src/MaaFramework.Binding.Native/Interop/AgentServer/MaaAgentServer.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记 +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace MaaFramework.Binding.Interop.Native; + +public static partial class MaaAgentServer +{ + [LibraryImport("MaaAgentServer", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool MaaAgentServerRegisterCustomRecognition(string name, MaaCustomRecognitionCallback recognition, nint transArg); + + [LibraryImport("MaaAgentServer", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool MaaAgentServerRegisterCustomAction(string name, MaaCustomActionCallback action, nint transArg); + + [LibraryImport("MaaAgentServer", StringMarshalling = StringMarshalling.Utf8)] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool MaaAgentServerStartUp(string identifier); + + [LibraryImport("MaaAgentServer", StringMarshalling = StringMarshalling.Utf8)] + public static partial void MaaAgentServerShutDown(); + + [LibraryImport("MaaAgentServer", StringMarshalling = StringMarshalling.Utf8)] + public static partial void MaaAgentServerJoin(); + + [LibraryImport("MaaAgentServer", StringMarshalling = StringMarshalling.Utf8)] + public static partial void MaaAgentServerDetach(); +} diff --git a/src/MaaFramework.Binding.Native/Interop/MaaCustomExtensions.cs b/src/MaaFramework.Binding.Native/Interop/MaaCustomExtensions.cs index 1363caf..2e52c80 100644 --- a/src/MaaFramework.Binding.Native/Interop/MaaCustomExtensions.cs +++ b/src/MaaFramework.Binding.Native/Interop/MaaCustomExtensions.cs @@ -44,7 +44,8 @@ nint transArg ActionParam: customActionParam, RecognitionDetail: recognitionDetail, RecognitionBox: new MaaRectBuffer(boxHandle) - ) + ), + new RunResults() ); }; return callback; diff --git a/src/MaaFramework.Binding.Native/Interop/NativeLibrary.cs b/src/MaaFramework.Binding.Native/Interop/NativeLibrary.cs index b2fd190..2cfd936 100644 --- a/src/MaaFramework.Binding.Native/Interop/NativeLibrary.cs +++ b/src/MaaFramework.Binding.Native/Interop/NativeLibrary.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace MaaFramework.Binding.Interop.Native; @@ -7,79 +8,124 @@ internal static partial class NativeLibrary { private static readonly Assembly s_assembly = typeof(NativeLibrary).Assembly; - public static void Init() - => SetDllImportResolver(s_assembly, NativeAssemblyResolver); +#pragma warning disable CA2255 // 不应在库中使用 “ModuleInitializer” 属性 +#pragma warning disable S2223 // Non-constant static fields should not be visible - public static IntPtr NativeAssemblyResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) + internal static bool IsLoaded; + internal static string LoadedDirectory = string.Empty; + internal static readonly Dictionary LoadedLibraryHandles = []; + + internal static ApiInfoFlags ApiInfo; + internal static readonly List SearchPath = []; + + [ModuleInitializer] + internal static void SetNativeLibraryResolver() => SetDllImportResolver(s_assembly, NativeLibraryResolver); + +#pragma warning restore S2223 // Non-constant static fields should not be visible +#pragma warning restore CA2255 // 不应在库中使用 “ModuleInitializer” 属性 + + public static nint NativeLibraryResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) => libraryName switch { - var libHandle = IntPtr.Zero; - if (!libraryName.Equals("MaaFramework", StringComparison.Ordinal) - && !libraryName.Equals("MaaToolkit", StringComparison.Ordinal)) - { - return libHandle; - } + "MaaFramework" or "MaaToolkit" + or "MaaAgentServer" or "MaaAgentClient" => GetLibraryHandle(libraryName), - if (TryGetRuntimesPath(libraryName, out var dllPath)) - { - _ = TryLoad(dllPath, assembly, searchPath, out libHandle); - } - return libHandle; + _ => IntPtr.Zero, + }; + + private static nint GetLibraryHandle(string libraryName) + { + if (LoadedLibraryHandles.TryGetValue(libraryName, out var libraryHandle)) + return libraryHandle; + + IsLoaded = true; + var resolver = TryGetRuntimesPath(libraryName, out var dllPath) && TryLoad(dllPath, out libraryHandle) + ? ApiInfoFlags.UseBindingResolver + : ApiInfoFlags.UseDefaultResolver; + SetBindingContext( + resolver, + dllDir: Path.GetDirectoryName(dllPath) ?? string.Empty, + isFirst: LoadedLibraryHandles.Count == 0); + + LoadedLibraryHandles.Add(libraryName, libraryHandle); + return libraryHandle; + } + + private static void SetBindingContext(ApiInfoFlags resolver, string dllDir, bool isFirst) + { + if (ApiInfo.HasFlag_ResolverExcept(resolver)) + throw new InvalidOperationException($"The resolver '{ApiInfo}' was attempted to switch to '{resolver}'."); + + if (isFirst) + LoadedDirectory = dllDir; + + if (LoadedDirectory != dllDir) + throw new InvalidOperationException($"The native library directory '{LoadedDirectory}' was attempted to switch to '{dllDir}'."); + + ApiInfo |= resolver; + if (!ApiInfo.HasFlag_Context()) + ApiInfo |= ApiInfoFlags.InFrameworkContext; } private static bool TryGetRuntimesPath(string libraryName, out string dllPath) { + libraryName = GetFullLibraryName(libraryName); dllPath = GetRuntimesPaths(libraryName).FirstOrDefault(File.Exists, string.Empty); return !string.IsNullOrEmpty(dllPath); } - private static IEnumerable GetRuntimesPaths(string libraryName) + private static IEnumerable GetRuntimesPaths(string libraryFullName) { - GetArchitectureNameAndExtensionName(out var arch, out var ext); - var args1 = new string[] - { - Path.GetDirectoryName(s_assembly.Location) ?? "./", + var searchPaths = SearchPath.Concat( + [ + Environment.GetEnvironmentVariable("MAAFW_BINARY_PATH"), + Path.GetDirectoryName(s_assembly.Location), Environment.CurrentDirectory, - }; - var args2 = new string[] - { - $"/runtimes/{arch}/native/", - "/" - }; - var args3 = new string[] + ]).Where(path => !string.IsNullOrWhiteSpace(path)); + + var runtimePaths = new[] { - $"{libraryName}.{ext}", - $"lib{libraryName}.{ext}" + "./", + $"./runtimes/{GetArchitectureName()}/native/", }; - return from arg1 in args1 - from arg2 in args2 - from arg3 in args3 + return from searchPath in searchPaths + from runtimePath in runtimePaths select Path.GetFullPath( - string.Concat(arg1, arg2, arg3)); + Path.Combine(searchPath, runtimePath, libraryFullName)); } - private static void GetArchitectureNameAndExtensionName(out string arch, out string ext) +#pragma warning disable IDE0072 // 添加缺失的事例 + private static string GetArchitectureName() => RuntimeInformation.OSArchitecture switch + { + Architecture.X64 when IsWindows => "win-x64", + // Architecture.Arm64 when IsWindows => "win-arm64", + Architecture.X64 when IsLinux => "linux-x64", + Architecture.Arm64 when IsLinux => "linux-arm64", + Architecture.X64 when IsOSX => "osx-x64", + Architecture.Arm64 when IsOSX => "osx-arm64", + Architecture.X64 when IsAndroid => "android-x64", + Architecture.Arm64 when IsAndroid => "android-arm64", + _ => throw new PlatformNotSupportedException(), + }; +#pragma warning restore IDE0072 // 添加缺失的事例 + + private static string GetFullLibraryName(string libraryName) { - if (IsWindows) arch = "win"; - else if (IsLinux) arch = "linux"; - else if (IsOSX) arch = "osx"; - else if (IsAndroid) arch = "android"; - else throw new PlatformNotSupportedException(); - - if (IsX64) arch += "-x64"; - else if (IsArm64) arch += "-arm64"; - else throw new PlatformNotSupportedException(); - - if (IsWindows) ext = "dll"; - else if (IsLinux || IsAndroid) ext = "so"; - else if (IsOSX) ext = "dylib"; - else throw new PlatformNotSupportedException(); + if (libraryName == "MaaFramework" && ApiInfo.HasFlag(ApiInfoFlags.InAgentServerContext)) + libraryName = "MaaAgentServer"; + + if (IsWindows) + return $"{libraryName}.dll"; + if (IsLinux || IsAndroid) + return $"lib{libraryName}.so"; + if (IsOSX) + return $"lib{libraryName}.dylib"; + + throw new PlatformNotSupportedException(); } private static bool IsWindows => OperatingSystem.IsWindows(); private static bool IsLinux => OperatingSystem.IsLinux(); private static bool IsOSX => OperatingSystem.IsMacOS(); private static bool IsAndroid => OperatingSystem.IsAndroid(); - private static bool IsX64 => RuntimeInformation.OSArchitecture == Architecture.X64; - private static bool IsArm64 => RuntimeInformation.OSArchitecture == Architecture.Arm64; } diff --git a/src/MaaFramework.Binding.Native/MaaAgentClient.cs b/src/MaaFramework.Binding.Native/MaaAgentClient.cs new file mode 100644 index 0000000..8ac875a --- /dev/null +++ b/src/MaaFramework.Binding.Native/MaaAgentClient.cs @@ -0,0 +1,220 @@ +using MaaFramework.Binding.Abstractions; +using MaaFramework.Binding.Buffers; +using MaaFramework.Binding.Interop.Native; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using static MaaFramework.Binding.Interop.Native.MaaAgentClient; + +namespace MaaFramework.Binding; + +/// +/// A wrapper class providing a reference implementation for . +/// +[DebuggerDisplay("{DebuggerDisplay,nq}")] +public class MaaAgentClient : MaaDisposableHandle, IMaaAgentClient +{ + private bool _isConnected; + private Process? _agentServerProcess; + + [ExcludeFromCodeCoverage(Justification = "Debugger display.")] + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string DebuggerDisplay => IsInvalid + ? $"Invalid {GetType().Name}" + : $"{GetType().Name} {{ Id = {Id}, IsConnected = {_isConnected} }}"; + + /// + /// Creates a instance. + /// + /// The unique identifier used to communicate with the agent server. + /// + /// Wrapper of . + /// + protected MaaAgentClient(string identifier = "") + : base(invalidHandleValue: MaaAgentClientHandle.Zero) + { + var handle = MaaAgentClientCreate(); + SetHandle(handle, needReleased: true); + Id = CreateSocket(identifier).ThrowIfNull(); + + if (!string.IsNullOrEmpty(identifier)) + _ = Id.ThrowIfNotEquals(identifier); + } + + /// + /// Creates a instance. + /// + /// The unique identifier used to communicate with the agent server. + /// The resource. + /// The instance. + public static MaaAgentClient Create(string identifier, MaaResource resource) + => new(identifier) { Resource = resource, }; + + /// + public static MaaAgentClient Create(MaaResource resource) + => new() { Resource = resource, }; + + /// + public string Id { get; } + + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + KillAndDisposeAgentServerProcess(); + } + + /// + /// + /// Wrapper of . + /// + protected override void ReleaseHandle() + => MaaAgentClientDestroy(Handle); + + /// + IMaaResource IMaaAgentClient.Resource + { + get => Resource; + set => Resource = (MaaResource)value; + } + + /// + /// + /// Wrapper of . + /// + public required MaaResource Resource + { + get => field; + set + { + ArgumentNullException.ThrowIfNull(value); + _ = MaaAgentClientBindResource(Handle, value.Handle).ThrowIfFalse(MaaInteroperationException.ResourceBindingFailedMessage); + field = value; + } + } + + /// + /// Creates a socket connection with the specified identifier. + /// + /// The specified identifier. + /// if the socket was created successfully; otherwise, . + /// + /// Wrapper of . + /// + protected string? CreateSocket(string identifier = "") + => MaaStringBuffer.TryGetValue(out var socketId, handle + => MaaStringBuffer.TrySetValue(handle, identifier) + && MaaAgentClientCreateSocket(Handle, handle)) + ? socketId + : null; + + /// + /// + /// Wrapper of . + /// + public bool LinkStart() + => _isConnected = MaaAgentClientConnect(Handle); + + /// + /// + /// Wrapper of . + /// + public bool LinkStart(ProcessStartInfo info, CancellationToken cancellationToken = default) + { + if (_agentServerProcess is null or { HasExited: true }) + { + _agentServerProcess?.Dispose(); + _agentServerProcess = Process.Start(info); + + if (_agentServerProcess is null or { HasExited: true }) + return false; + } + + return LinkStartUnlessProcessExit(_agentServerProcess, cancellationToken).GetAwaiter().GetResult(); + } + + /// + /// + /// Wrapper of . + /// + public bool LinkStart(IMaaAgentClient.AgentServerStartupMethod method, CancellationToken cancellationToken = default) + { + if (_agentServerProcess is null or { HasExited: true }) + { + _agentServerProcess?.Dispose(); + _agentServerProcess = method.Invoke(Id, NativeBindingContext.LoadedNativeLibraryDirectory); + + if (_agentServerProcess is null or { HasExited: true }) + return false; + } + + return LinkStartUnlessProcessExit(_agentServerProcess, cancellationToken).GetAwaiter().GetResult(); + } + + /// + public async Task LinkStartUnlessProcessExit(Process process, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(process); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + if (process.HasExited) + return false; + + var serverExitTask = process.WaitForExitAsync(cts.Token); + var linkStartTask = Task.Run(LinkStart, cts.Token); + var completedTask = await Task.WhenAny(linkStartTask, serverExitTask).ConfigureAwait(false); + + try + { + cts.Token.ThrowIfCancellationRequested(); + if (completedTask == serverExitTask) + return false; + + return linkStartTask.Result; + } + finally + { +#if NET8_0_OR_GREATER + await cts.CancelAsync(); +#else + cts.Cancel(); +#endif + } + } + + /// + /// + /// Wrapper of . + /// + public bool LinkStop() + { + if (_isConnected) + { + _isConnected = false; + if (!MaaAgentClientDisconnect(Handle)) + { + _isConnected = true; + return false; + } + } + + return true; + } + + /// + public Process AgentServerProcess => _agentServerProcess + ?? throw new InvalidOperationException($"The agent server process is unavailable or not managed by {nameof(MaaAgentClient)}."); + + private void KillAndDisposeAgentServerProcess() + { + if (_agentServerProcess is null) + return; + + if (!_agentServerProcess.HasExited) + { + _agentServerProcess.Kill(entireProcessTree: true); + _agentServerProcess.WaitForExit(); + } + + _agentServerProcess.Dispose(); + _agentServerProcess = null; + } +} diff --git a/src/MaaFramework.Binding.Native/MaaAgentServer.cs b/src/MaaFramework.Binding.Native/MaaAgentServer.cs new file mode 100644 index 0000000..7bfa192 --- /dev/null +++ b/src/MaaFramework.Binding.Native/MaaAgentServer.cs @@ -0,0 +1,152 @@ +using MaaFramework.Binding.Custom; +using MaaFramework.Binding.Interop.Native; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using static MaaFramework.Binding.Interop.Native.MaaAgentServer; + +namespace MaaFramework.Binding; + +/// +/// A wrapper class providing a reference implementation for . +/// +[DebuggerDisplay("{DebuggerDisplay,nq}")] +public sealed class MaaAgentServer : IMaaAgentServer +{ + /// + /// Gets the unique identifier used to communicate with the agent client. + /// + public static string CurrentId { get; private set; } + + /// + /// Gets the current instance. + /// + public static MaaAgentServer Current { get; } + + /// + /// Creates a instance. + /// + private MaaAgentServer() { } + static MaaAgentServer() + { + NativeBindingContext.SwitchToAgentServerContext(); + CurrentId = string.Empty; + Current = new(); + } + + private readonly MaaMarshaledApiRegistry _actions = new(); + private readonly MaaMarshaledApiRegistry _recognitions = new(); + + [ExcludeFromCodeCoverage(Justification = "Debugger display.")] + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string DebuggerDisplay => $"{GetType().Name} {{ {nameof(CurrentId)} = {CurrentId}, CustomActions = [{string.Join(", ", _actions.Names)}] , CustomRecognitions = [{string.Join(" & ", _recognitions.Names)}] }}"; + + IMaaAgentServer IMaaAgentServer.WithIdentifier(string identifier) => WithIdentifier(identifier); + IMaaAgentServer IMaaAgentServer.Register(string name, T custom) => Register(name, custom); + IMaaAgentServer IMaaAgentServer.Register(T custom) => Register(custom); + IMaaAgentServer IMaaAgentServer.StartUp() => StartUp(); + IMaaAgentServer IMaaAgentServer.ShutDown() => ShutDown(); + IMaaAgentServer IMaaAgentServer.Join() => Join(); + IMaaAgentServer IMaaAgentServer.Detach() => Detach(); + + /// + public MaaAgentServer WithIdentifier(string identifier) + { + CurrentId = identifier; + return this; + } + + /// + public MaaAgentServer Register(string name, T custom) where T : IMaaCustomResource + { + custom.Name = name; + return Register(custom); + } + + /// + /// + /// Wrapper of and . + /// + public MaaAgentServer Register(T custom) where T : IMaaCustomResource + { + var ret = custom switch + { + IMaaCustomAction res + => MaaAgentServerRegisterCustomAction(res.Name, res.Convert(out var callback), nint.Zero) + && _actions.Register(res.Name, callback), + IMaaCustomRecognition res + => MaaAgentServerRegisterCustomRecognition(res.Name, res.Convert(out var callback), nint.Zero) + && _recognitions.Register(res.Name, callback), + _ + => throw new NotImplementedException($"Type '{typeof(T)}' is not implemented."), + }; + _ = ret.ThrowIfFalse(); + return this; + } + + /// + /// + /// Wrapper of . + /// + public MaaAgentServer StartUp() + { + if (string.IsNullOrEmpty(CurrentId)) + throw new InvalidOperationException("Identifier is not set. Use 'WithIdentifier' method to set it."); + _ = MaaAgentServerStartUp(CurrentId).ThrowIfFalse(); + return this; + } + + /// + /// + /// Wrapper of . + /// + public MaaAgentServer ShutDown() + { + MaaAgentServerShutDown(); + return this; + } + + /// + /// + /// Wrapper of . + /// + public MaaAgentServer Join() + { + MaaAgentServerJoin(); + return this; + } + + /// + /// + /// Wrapper of . + /// + public MaaAgentServer Detach() + { + MaaAgentServerDetach(); + return this; + } +} + +/// +/// A static class providing extension methods for . +/// +public static class MaaAgentServerExtensions +{ + /// + /// + public static MaaAgentServer WithToolkitConfig_InitOption(this MaaAgentServer server, string userPath = nameof(Environment.CurrentDirectory), [StringSyntax("Json")] string defaultJson = "{}") + { + _ = MaaToolkit.Shared.Config.InitOption(userPath, defaultJson).ThrowIfFalse(); + return server; + } + + /// + /// Configures the MaaAgentServer to use the specified native libraries. + /// + /// The server. + /// The directory paths to search for native libraries. + public static MaaAgentServer WithNativeLibrary(this MaaAgentServer server, params string[] paths) + { + NativeBindingContext.AppendNativeLibrarySearchPaths(paths); + return server; + } +} diff --git a/src/MaaFramework.Binding.Native/MaaContext.cs b/src/MaaFramework.Binding.Native/MaaContext.cs index ff99598..a52a75d 100644 --- a/src/MaaFramework.Binding.Native/MaaContext.cs +++ b/src/MaaFramework.Binding.Native/MaaContext.cs @@ -22,13 +22,16 @@ public MaaContext(MaaContextHandle contextHandle) if (contextHandle == MaaContextHandle.Zero) throw new ArgumentException($"Value cannot be {MaaContextHandle.Zero}.", nameof(contextHandle)); Handle = contextHandle; + + var taskerHandle = MaaContextGetTasker(Handle); + Tasker = NativeBindingContext.IsStatelessMode ? new MaaTasker(taskerHandle) : MaaTasker.Instances[taskerHandle]; } /// /// /// Wrapper of . /// - public TaskDetail? RunTask(string entry, [StringSyntax("Json")] string pipelineOverride) + public TaskDetail? RunTask(string entry, [StringSyntax("Json")] string pipelineOverride = "{}") { var taskId = MaaContextRunTask(Handle, entry, pipelineOverride); return taskId == Interop.Native.MaaDef.MaaInvalidId @@ -37,14 +40,14 @@ public MaaContext(MaaContextHandle contextHandle) } /// - public RecognitionDetail? RunRecognition(string entry, [StringSyntax("Json")] string pipelineOverride, IMaaImageBuffer image) - => RunRecognition(entry, pipelineOverride, (MaaImageBuffer)image); + public RecognitionDetail? RunRecognition(string entry, IMaaImageBuffer image, [StringSyntax("Json")] string pipelineOverride = "{}") + => RunRecognition(entry, (MaaImageBuffer)image, pipelineOverride); /// /// /// Wrapper of . /// - public RecognitionDetail? RunRecognition(string entry, [StringSyntax("Json")] string pipelineOverride, MaaImageBuffer image) + public RecognitionDetail? RunRecognition(string entry, MaaImageBuffer image, [StringSyntax("Json")] string pipelineOverride = "{}") { ArgumentNullException.ThrowIfNull(image); var recognitionId = MaaContextRunRecognition(Handle, entry, pipelineOverride, image.Handle); @@ -54,14 +57,14 @@ public MaaContext(MaaContextHandle contextHandle) } /// - public NodeDetail? RunAction(string entry, [StringSyntax("Json")] string pipelineOverride, IMaaRectBuffer recognitionBox, string recognitionDetail) - => RunAction(entry, pipelineOverride, (MaaRectBuffer)recognitionBox, recognitionDetail); + public NodeDetail? RunAction(string entry, IMaaRectBuffer recognitionBox, string recognitionDetail, [StringSyntax("Json")] string pipelineOverride = "{}") + => RunAction(entry, (MaaRectBuffer)recognitionBox, recognitionDetail, pipelineOverride); /// /// /// Wrapper of . /// - public NodeDetail? RunAction(string entry, [StringSyntax("Json")] string pipelineOverride, MaaRectBuffer recognitionBox, string recognitionDetail) + public NodeDetail? RunAction(string entry, MaaRectBuffer recognitionBox, string recognitionDetail, [StringSyntax("Json")] string pipelineOverride = "{}") { ArgumentNullException.ThrowIfNull(recognitionBox); var nodeId = MaaContextRunAction(Handle, entry, pipelineOverride, recognitionBox.Handle, recognitionDetail); @@ -97,7 +100,7 @@ public bool OverrideNext(string nodeName, IEnumerable nextList) /// /// Wrapper of . /// - public MaaTasker Tasker => MaaTasker.Instances[MaaContextGetTasker(Handle)]; + public MaaTasker Tasker { get; } object ICloneable.Clone() => Clone(); diff --git a/src/MaaFramework.Binding.Native/MaaController.cs b/src/MaaFramework.Binding.Native/MaaController.cs index e0d2317..8dfdca4 100644 --- a/src/MaaFramework.Binding.Native/MaaController.cs +++ b/src/MaaFramework.Binding.Native/MaaController.cs @@ -11,7 +11,7 @@ namespace MaaFramework.Binding; /// A wrapper class providing a reference implementation for . /// [DebuggerDisplay("{DebuggerDisplay,nq}")] -public abstract class MaaController : MaaCommon, IMaaController +public class MaaController : MaaCommon, IMaaController { [ExcludeFromCodeCoverage(Justification = "Debugger display.")] [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -19,6 +19,11 @@ public abstract class MaaController : MaaCommon, IMaaController ? $"Invalid {GetType().Name}" : $"{GetType().Name} {{ }}"; + internal MaaController(MaaControllerHandle handle) + { + SetHandle(handle, needReleased: false); + } + /// /// Creates a instance. /// diff --git a/src/MaaFramework.Binding.Native/MaaResource.cs b/src/MaaFramework.Binding.Native/MaaResource.cs index d2074b6..3c15f53 100644 --- a/src/MaaFramework.Binding.Native/MaaResource.cs +++ b/src/MaaFramework.Binding.Native/MaaResource.cs @@ -9,14 +9,19 @@ namespace MaaFramework.Binding; /// /// A wrapper class providing a reference implementation for . /// -public class MaaResource : MaaCommon, IMaaResource +public class MaaResource : MaaCommon, IMaaResource { private readonly HashSet _postedPaths = []; /// public override string ToString() => IsInvalid ? $"Invalid {GetType().Name}" - : $"{GetType().Name} {{ Paths = {string.Join(" & ", _postedPaths)}, CustomActions = {string.Join(" & ", _actions.Names)}, CustomRecognitions = {string.Join(" & ", _recognitions.Names)} }}"; + : $"{GetType().Name} {{ Paths = [{string.Join(", ", _postedPaths)}], CustomActions = [{string.Join(", ", _actions.Names)}] , CustomRecognitions = [{string.Join(" & ", _recognitions.Names)}] }}"; + + internal MaaResource(MaaResourceHandle handle) + { + SetHandle(handle, needReleased: false); + } /// /// Creates a instance. diff --git a/src/MaaFramework.Binding.Native/MaaTasker.cs b/src/MaaFramework.Binding.Native/MaaTasker.cs index 2e1f403..1839f20 100644 --- a/src/MaaFramework.Binding.Native/MaaTasker.cs +++ b/src/MaaFramework.Binding.Native/MaaTasker.cs @@ -28,6 +28,19 @@ public class MaaTasker : MaaCommon, IMaaTasker /// protected internal static ConcurrentDictionary Instances { get; } = []; +#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑添加 "required" 修饰符或声明为可为 null。 + [SetsRequiredMembers] + internal MaaTasker(MaaTaskerHandle handle) + { + SetHandle(handle, needReleased: false); + _resource = new MaaResource(MaaTaskerGetResource(handle)); + _controller = new MaaController(MaaTaskerGetController(handle)); + DisposeOptions = DisposeOptions.None; + Toolkit = MaaToolkit.Shared; + Utility = MaaUtility.Shared; + } +#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑添加 "required" 修饰符或声明为可为 null。 + /// /// Creates a instance. /// @@ -43,8 +56,10 @@ public MaaTasker(bool toolkitInit = false) throw new InvalidOperationException($"This {nameof(MaaTasker)} already added to {nameof(Instances)}."); SetHandle(handle, needReleased: true); - Toolkit = new MaaToolkit(toolkitInit); - Utility = new MaaUtility(); + Toolkit = MaaToolkit.Shared; + Utility = MaaUtility.Shared; + if (toolkitInit) + _ = Toolkit.Config.InitOption().ThrowIfFalse(); } /// The controller. @@ -67,18 +82,13 @@ public MaaTasker(MaaController controller, MaaResource resource, DisposeOptions /// protected override void Dispose(bool disposing) { - // Cannot destroy Instance before disposing Controller and Resource. - if (DisposeOptions.HasFlag(DisposeOptions.Controller)) - { Controller.Dispose(); - } if (DisposeOptions.HasFlag(DisposeOptions.Resource)) - { Resource.Dispose(); - } + _ = Instances.TryRemove(new KeyValuePair(Handle, this)); base.Dispose(disposing); } @@ -109,6 +119,9 @@ public bool SetOption(TaskerOption opt, T value) #pragma warning restore } + private MaaResource _resource = null!; + private MaaController _controller = null!; + IMaaResource IMaaTasker.Resource { get => Resource; @@ -130,14 +143,14 @@ public required MaaResource Resource get { if (!IsInvalid) - _ = MaaTaskerGetResource(Handle).ThrowIfNotEquals(field.Handle, MaaInteroperationException.ResourceModifiedMessage); - return field; + _ = MaaTaskerGetResource(Handle).ThrowIfNotEquals(_resource.Handle, MaaInteroperationException.ResourceModifiedMessage); + return _resource; } set { ArgumentNullException.ThrowIfNull(value); _ = MaaTaskerBindResource(Handle, value.Handle).ThrowIfFalse(MaaInteroperationException.ResourceBindingFailedMessage); - field = value; + _resource = value; } } @@ -150,14 +163,14 @@ public required MaaController Controller get { if (!IsInvalid) - _ = MaaTaskerGetController(Handle).ThrowIfNotEquals(field.Handle, MaaInteroperationException.ControllerModifiedMessage); - return field; + _ = MaaTaskerGetController(Handle).ThrowIfNotEquals(_controller.Handle, MaaInteroperationException.ControllerModifiedMessage); + return _controller; } set { ArgumentNullException.ThrowIfNull(value); _ = MaaTaskerBindController(Handle, value.Handle).ThrowIfFalse(MaaInteroperationException.ControllerBindingFailedMessage); - field = value; + _controller = value; } } diff --git a/src/MaaFramework.Binding.Native/MaaToolkit.cs b/src/MaaFramework.Binding.Native/MaaToolkit.cs index 357ce6e..7c514e1 100644 --- a/src/MaaFramework.Binding.Native/MaaToolkit.cs +++ b/src/MaaFramework.Binding.Native/MaaToolkit.cs @@ -12,6 +12,11 @@ namespace MaaFramework.Binding; /// public class MaaToolkit : IMaaToolkit { + /// + /// Gets the shared instance. + /// + public static MaaToolkit Shared { get; } = new(); + /// /// Creates a instance. /// diff --git a/src/MaaFramework.Binding.Native/MaaUtility.cs b/src/MaaFramework.Binding.Native/MaaUtility.cs index af10545..2d8cbec 100644 --- a/src/MaaFramework.Binding.Native/MaaUtility.cs +++ b/src/MaaFramework.Binding.Native/MaaUtility.cs @@ -8,6 +8,11 @@ namespace MaaFramework.Binding; /// public class MaaUtility : IMaaUtility { + /// + /// Gets the shared instance. + /// + public static MaaUtility Shared { get; } = new(); + /// /// /// Wrapper of . diff --git a/src/MaaFramework.Binding.Native/NativeBindingContext.cs b/src/MaaFramework.Binding.Native/NativeBindingContext.cs new file mode 100644 index 0000000..1201dae --- /dev/null +++ b/src/MaaFramework.Binding.Native/NativeBindingContext.cs @@ -0,0 +1,85 @@ +using MaaFramework.Binding.Interop.Native; +using System.Diagnostics; + +namespace MaaFramework.Binding; + +/// +/// Provides information and configuration for native bindings in the MaaFramework. +/// +public static class NativeBindingContext +{ + /// + /// Gets a value indicating whether NativeLibrary is already loaded. + /// + public static bool IsLoaded => NativeLibrary.IsLoaded; + + /// + /// Gets the loaded directory path where native libraries are located. + /// + public static string LoadedNativeLibraryDirectory + { + get + { + if (!NativeLibrary.ApiInfo.HasFlag(ApiInfoFlags.UseDefaultResolver)) + return NativeLibrary.LoadedDirectory; + + var name = NativeLibrary.LoadedLibraryHandles.First().Key; + foreach (var obj in Process.GetCurrentProcess().Modules) + { + if (obj is not ProcessModule module || Path.GetFileNameWithoutExtension(module.ModuleName) != name) + continue; + return Path.GetDirectoryName(module.FileName) ?? string.Empty; + } + return string.Empty; + } + } + + /// + /// Gets the API information, which provides details about the current API context. + /// + public static ApiInfoFlags ApiInfo => NativeLibrary.ApiInfo; + + /// + /// Gets a value indicating whether the current API is interoperating in the stateless mode. + /// Stateless mode is typically used in server contexts. + /// + public static bool IsStatelessMode => ApiInfo.HasFlag(ApiInfoFlags.InAgentServerContext); + + /// + /// Switches the context to the MaaAgentServer context. + /// + /// NativeLibrary is already loaded. + public static void SwitchToAgentServerContext() + { + ThrowIfLoaded(); + NativeLibrary.ApiInfo = ApiInfoFlags.InAgentServerContext; + } + + /// + /// Switches the context to the MaaFramework context. + /// + /// NativeLibrary is already loaded. + public static void SwitchToFrameworkContext() + { + ThrowIfLoaded(); + NativeLibrary.ApiInfo = ApiInfoFlags.InFrameworkContext; + } + + /// + /// Appends the specified paths to the native library search paths. + /// + /// + /// NativeLibrary is already loaded. + public static void AppendNativeLibrarySearchPaths(params IEnumerable paths) + { + ThrowIfLoaded(); + NativeLibrary.SearchPath.AddRange(paths); + } + + /// NativeLibrary is already loaded. + internal static void ThrowIfLoaded() + { + if (NativeLibrary.IsLoaded) + throw new InvalidOperationException("NativeLibrary is already loaded."); + } +} diff --git a/src/MaaFramework.Binding.UnitTests/MaaFramework.Binding.UnitTests.csproj b/src/MaaFramework.Binding.UnitTests/MaaFramework.Binding.UnitTests.csproj index 1078b2b..e116e79 100644 --- a/src/MaaFramework.Binding.UnitTests/MaaFramework.Binding.UnitTests.csproj +++ b/src/MaaFramework.Binding.UnitTests/MaaFramework.Binding.UnitTests.csproj @@ -5,25 +5,20 @@ - - + + + PreserveNewest - - - - - + false $(NoWarn);S1121,S1656,S1199,IDE0022,IDE0060,IDE0072 - - $(DefineConstants);MAA_NATIVE; diff --git a/src/MaaFramework.Binding.UnitTests/Properties/launchSettings.json b/src/MaaFramework.Binding.UnitTests/Properties/launchSettings.json new file mode 100644 index 0000000..6b50930 --- /dev/null +++ b/src/MaaFramework.Binding.UnitTests/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "MaaFramework.Binding.UnitTests": { + "commandName": "Project", + "commandLineArgs": "CurrentDirectory CurrentDirectory 6CDC213A-085C-40C8-8665-635820D10425" + } + } +} \ No newline at end of file diff --git a/src/MaaFramework.Binding.UnitTests/Test_Buffers.cs b/src/MaaFramework.Binding.UnitTests/Test_Buffers.cs index 6fa19f1..29b7f4c 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_Buffers.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_Buffers.cs @@ -22,9 +22,9 @@ public class Test_Buffers new MaaStringBuffer(), new MaaImageListBuffer(), new MaaStringListBuffer(), - (AdbDeviceListBuffer)new MaaToolkit().AdbDevice.Find(), + (AdbDeviceListBuffer)MaaToolkit.Shared.AdbDevice.Find(), #if MAA_WIN32 - (DesktopWindowListBuffer)new MaaToolkit().Desktop.Window.Find(), + (DesktopWindowListBuffer)MaaToolkit.Shared.Desktop.Window.Find(), #endif ] }, @@ -1101,6 +1101,7 @@ public bool ThrowOnInvalid get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public bool IsStateless => throw new NotImplementedException(); public bool IsEmpty => throw new NotImplementedException(); public bool TryClear() => throw new NotImplementedException(); public ImageInfo GetInfo() => throw new NotImplementedException(); @@ -1126,6 +1127,7 @@ public bool ThrowOnInvalid get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public bool IsStateless => throw new NotImplementedException(); public bool IsEmpty => throw new NotImplementedException(); public ulong Size => throw new NotImplementedException(); public bool TryClear() => throw new NotImplementedException(); @@ -1143,6 +1145,7 @@ public bool ThrowOnInvalid get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public bool IsStateless => throw new NotImplementedException(); public int X => throw new NotImplementedException(); public int Y => throw new NotImplementedException(); public int Width => throw new NotImplementedException(); diff --git a/src/MaaFramework.Binding.UnitTests/Test_Common.cs b/src/MaaFramework.Binding.UnitTests/Test_Common.cs index 8594752..4305396 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_Common.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_Common.cs @@ -27,7 +27,7 @@ private static void InitializeInfo(TestContext testContext) #if GITHUB_ACTIONS // use environment "AdbPath" AdbDeviceInfo[] devices = []; #else - var devices = new MaaToolkit().AdbDevice.Find(); + var devices = MaaToolkit.Shared.AdbDevice.Find(); #endif // 请修改 TestParam.runsettings,并在测试资源管理器——设置——配置运行设置 @@ -52,8 +52,8 @@ public static void InitializeAssembly(TestContext testContext) { ArgumentNullException.ThrowIfNull(testContext); - _ = new MaaUtility().SetOption(GlobalOption.LogDir, DebugPath); - _ = new MaaUtility().SetOption(GlobalOption.StdoutLevel, LoggingLevel.Off); + _ = MaaUtility.Shared.SetOption_LogDir(DebugPath); + _ = MaaUtility.Shared.SetOption_StdoutLevel(LoggingLevel.Off); InitializeInfo(testContext); } diff --git a/src/MaaFramework.Binding.UnitTests/Test_Custom.cs b/src/MaaFramework.Binding.UnitTests/Test_Custom.cs index f5822bb..9354d3a 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_Custom.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_Custom.cs @@ -35,7 +35,10 @@ public bool Analyze(in IMaaContext context, in AnalyzeArgs args, in AnalyzeResul Assert.AreEqual(NodeName, args.NodeName); Assert.AreEqual(RecognitionParam, args.RecognitionParam); - _ = Assert.ThrowsException(() => new MaaContext(IntPtr.Zero)); + _ = Assert.ThrowsException(() => +#if MAA_NATIVE + new MaaContext(IntPtr.Zero)); +#endif var cloneContext = (context as ICloneable).Clone() as IMaaContext; cloneContext = cloneContext?.Clone(); #if MAA_NATIVE @@ -43,14 +46,18 @@ public bool Analyze(in IMaaContext context, in AnalyzeArgs args, in AnalyzeResul #endif Assert.IsNotNull(cloneContext); Assert.IsNull( - cloneContext.RunRecognition(DiffEntry, "{}", (IMaaImageBuffer)args.Image)); - Assert.AreSame( - context.Tasker, cloneContext.Tasker); + cloneContext.RunRecognition(DiffEntry, args.Image)); + if (!context.Tasker.IsStateless) + { + Assert.AreSame( + context.Tasker, cloneContext.Tasker); + } + Assert.AreEqual( context.TaskJob.Id, cloneContext.TaskJob.Id); var recognitionDetail = - context.RunRecognition(DiffEntry, DiffParam, args.Image); + context.RunRecognition(DiffEntry, args.Image, DiffParam); Assert.IsNotNull( recognitionDetail?.HitBox); @@ -91,7 +98,7 @@ internal sealed class TestAction : IMaaCustomAction { public string Name { get; set; } = nameof(TestAction); - public bool Run(in IMaaContext context, in RunArgs args) + public bool Run(in IMaaContext context, in RunArgs args, in RunResults results) { Assert.AreEqual(NodeName, args.NodeName); Assert.AreEqual(ActionParam, args.ActionParam); @@ -99,13 +106,13 @@ public bool Run(in IMaaContext context, in RunArgs args) Assert.AreNotEqual(Detail, args.RecognitionDetail.Detail); Assert.AreEqual(Box, $"{args.RecognitionBox.X}{args.RecognitionBox.Y}{args.RecognitionBox.Width}{args.RecognitionBox.Height}"); - var nodeDetail = context.RunAction(DiffEntry, DiffParam, args.RecognitionBox, args.RecognitionDetail.Detail); + var nodeDetail = context.RunAction(DiffEntry, args.RecognitionBox, args.RecognitionDetail.Detail, DiffParam); Assert.IsNotNull(nodeDetail); return true; } } - internal sealed class TestController(MaaController c) : IMaaCustomController, IMaaDisposable + internal sealed class TestController(IMaaController c) : IMaaCustomController, IMaaDisposable { #region Test_IMaaDisposable @@ -117,6 +124,8 @@ public bool ThrowOnInvalid set => c.ThrowOnInvalid = value; } + public bool IsStateless => c.IsStateless; + public void Dispose() => c.Dispose(); #endregion @@ -137,7 +146,9 @@ public bool PressKey(int keycode) public bool RequestResolution(out int width, out int height) { +#if MAA_NATIVE using var image = new MaaImageBuffer(); +#endif if (Screencap(image)) { width = image.Width; diff --git a/src/MaaFramework.Binding.UnitTests/Test_IMaaAgentClient.cs b/src/MaaFramework.Binding.UnitTests/Test_IMaaAgentClient.cs new file mode 100644 index 0000000..240a311 --- /dev/null +++ b/src/MaaFramework.Binding.UnitTests/Test_IMaaAgentClient.cs @@ -0,0 +1,121 @@ +using MaaFramework.Binding.Abstractions; +using System.Diagnostics; + +namespace MaaFramework.Binding.UnitTests; + +/// +/// Test and . +/// +[TestClass] +// ReSharper disable InconsistentNaming +public class Test_IMaaAgentClient +{ + public static Dictionary NewData => new() + { +#if MAA_NATIVE + { MaaTypes.Native, MaaAgentClient.Create(new MaaResource()) }, +#endif + }; + public static Dictionary Data { get; private set; } = default!; + + [ClassInitialize] + public static void InitializeClass(TestContext context) + { + Data = NewData; + foreach (var data in Data.Values.Cast()) + { + Assert.IsFalse(data.IsInvalid); + } + } + + [ClassCleanup] + public static void CleanUpClass() + { + Common.DisposeData(Data.Values.Cast()); + } + + [TestMethod] + public void CreateInstances() + { +#if MAA_NATIVE + var newId = Guid.NewGuid().ToString(); + using var native1 = MaaAgentClient.Create(new MaaResource()); + using var native2 = MaaAgentClient.Create(new MaaResource()); + using var native3 = MaaAgentClient.Create(newId, new MaaResource()); + + Assert.AreNotEqual(native1.Id, native2.Id); + Assert.AreEqual(newId, native3.Id); +#endif + } + + [TestMethod] + [MaaData(MaaTypes.All, nameof(Data))] + public void Interface_Id_Resource(MaaTypes type, IMaaAgentClient maaAgentClient) + { + Assert.AreNotEqual(string.Empty, maaAgentClient.Id); + Assert.IsNotNull(maaAgentClient.Resource); + } + + [TestMethod] + [MaaData(MaaTypes.All, nameof(Data))] + public void Interface_LinkStart_LinkStop_AgentServerProcess(MaaTypes type, IMaaAgentClient maaAgentClient) + { + _ = Assert.ThrowsException(() => + maaAgentClient.AgentServerProcess); + var ret = maaAgentClient.LinkStart(StartupAgentServer); + Assert.IsTrue( + ret); + Assert.IsTrue( // double start + maaAgentClient.LinkStart()); + Assert.IsFalse( + maaAgentClient.AgentServerProcess.HasExited); + + Assert.IsTrue( + maaAgentClient.LinkStop()); + Assert.IsTrue( // double stop + maaAgentClient.LinkStop()); + Task.Delay(100).Wait(); // wait for process exit + Assert.IsTrue( + maaAgentClient.AgentServerProcess.HasExited); + } + + [TestMethod] + [MaaData(MaaTypes.All, nameof(Data))] + public void RunTask(MaaTypes type, IMaaAgentClient maaAgentClient) + { + using var maa = new MaaTasker + { + Controller = new MaaAdbController(Common.AdbPath, Common.Address, AdbScreencapMethods.Encode, AdbInputMethods.AdbShell, Common.AdbConfig, Common.AgentPath), + Resource = new MaaResource(), + DisposeOptions = DisposeOptions.All, + }; + Assert.IsTrue( + maa.IsInitialized); + + using var agent = MaaAgentClient.Create("6CDC213A-085C-40C8-8665-635820D10425", maa.Resource); + using (var cts = new CancellationTokenSource(10000)) + { + Assert.IsTrue( + // agent.LinkStart()); + agent.LinkStart(StartupAgentServer, cts.Token)); + } + var status = maa + .AppendTask(Custom.NodeName, Custom.Param) + .Wait(); + + Assert.AreEqual(MaaJobStatus.Succeeded, + status); + Assert.IsTrue( + agent.LinkStop()); + + } + + private static Process? StartupAgentServer(string identifier, string nativeAssemblyDirectory) + { + return Process.Start(new ProcessStartInfo( + "dotnet", $"{typeof(Test_IMaaAgentServer).Assembly.Location} {nativeAssemblyDirectory} {Environment.CurrentDirectory} {identifier}") + { + UseShellExecute = false, + }); + } +} diff --git a/src/MaaFramework.Binding.UnitTests/Test_IMaaAgentServer.cs b/src/MaaFramework.Binding.UnitTests/Test_IMaaAgentServer.cs new file mode 100644 index 0000000..de61aa6 --- /dev/null +++ b/src/MaaFramework.Binding.UnitTests/Test_IMaaAgentServer.cs @@ -0,0 +1,34 @@ +namespace MaaFramework.Binding.UnitTests; + +internal static class Test_IMaaAgentServer +{ + public static int Main() + { + var commandLineArgs = Environment.GetCommandLineArgs(); + if (commandLineArgs.Length < 4) + { + Console.WriteLine("Call AgentMain.cs instead of this file."); + return 1; + } + + var socketId = commandLineArgs[^1]; + var userPath = commandLineArgs[^2]; + var dllPath = commandLineArgs[^3]; + Test(socketId, userPath, dllPath); + + return 0; + } + + public static void Test(string id, string userPath, string dllPath) + { + _ = MaaAgentServer.Current // test double call + .WithIdentifier(id).WithIdentifier(id) + .WithNativeLibrary(dllPath).WithNativeLibrary(dllPath) + .WithToolkitConfig_InitOption(userPath).WithToolkitConfig_InitOption(userPath) + .Register(Custom.Recognition) // cat not double call from here + .Register(Custom.Action) + .StartUp() + .Join().Join() // test double call + .ShutDown().ShutDown(); + } +} diff --git a/src/MaaFramework.Binding.UnitTests/Test_IMaaController.cs b/src/MaaFramework.Binding.UnitTests/Test_IMaaController.cs index 72b2ea1..901a9db 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_IMaaController.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_IMaaController.cs @@ -63,7 +63,7 @@ static void InitializeData(AdbInputMethods inputPreset) .Wait() .ThrowIfNot(MaaJobStatus.Succeeded); Assert.IsTrue( - data.SetOption(ControllerOption.ScreenshotTargetShortSide, 720)); + data.SetOption_ScreenshotTargetShortSide(720)); } } } @@ -112,8 +112,7 @@ public void CreateInstances() #if !GITHUB_ACTIONS #region MaaWin32Controller - var toolkit = new MaaToolkit(); - var windowInfo = toolkit.Desktop.Window.Find().First(static x + var windowInfo = MaaToolkit.Shared.Desktop.Window.Find().First(static x => x.Name.Contains("Visual Studio", StringComparison.OrdinalIgnoreCase) || x.Name.Contains("Maa", StringComparison.OrdinalIgnoreCase)); diff --git a/src/MaaFramework.Binding.UnitTests/Test_IMaaResource.cs b/src/MaaFramework.Binding.UnitTests/Test_IMaaResource.cs index 0036dcc..c371e46 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_IMaaResource.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_IMaaResource.cs @@ -32,7 +32,7 @@ public static void InitializeClass(TestContext context) data.Callback += Common.NotificationHandlerRegistry.OnCallback; data.Callback += Common.OnResourceLoading.ToCallback(); - _ = data.SetOption(ResourceOption.InferenceDevice, InferenceDevice.CPU); + _ = data.SetOption_InferenceDevice(InferenceDevice.CPU); } } diff --git a/src/MaaFramework.Binding.UnitTests/Test_IMaaTasker.cs b/src/MaaFramework.Binding.UnitTests/Test_IMaaTasker.cs index 1e76282..84d66ab 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_IMaaTasker.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_IMaaTasker.cs @@ -52,15 +52,15 @@ public static void InitializeClass(TestContext context) .Wait() .ThrowIfNot(MaaJobStatus.Succeeded); _ = data.Resource - .SetOption(ResourceOption.InferenceDevice, InferenceDevice.CPU); + .SetOption_InferenceDevice(InferenceDevice.CPU); _ = data.Resource - .SetOption(ResourceOption.InferenceExecutionProvider, InferenceExecutionProvider.CPU); + .SetOption_InferenceExecutionProvider(InferenceExecutionProvider.CPU); _ = data.Controller .LinkStart() .Wait() .ThrowIfNot(MaaJobStatus.Succeeded); _ = data.Controller - .SetOption(ControllerOption.ScreenshotTargetShortSide, 720); + .SetOption_ScreenshotTargetShortSide(720); Assert.IsTrue(data.IsInitialized); } } @@ -328,7 +328,7 @@ public void MaaTaskJob_Query(MaaTypes type, IMaaTasker maaTasker, string taskEnt { Assert.IsNotNull(maaTasker); Assert.IsTrue( - maaTasker.Utility.SetOption(GlobalOption.DebugMode, debugMode)); + maaTasker.Utility.SetOption_DebugMode(debugMode)); var job = maaTasker.AppendTask(taskEntryName, diff); @@ -358,7 +358,7 @@ public void MaaTaskJob_Query(MaaTypes type, IMaaTasker maaTasker, string taskEnt } Assert.IsTrue( - maaTasker.Utility.SetOption(GlobalOption.DebugMode, false)); + maaTasker.Utility.SetOption_DebugMode(false)); } [TestMethod] diff --git a/src/MaaFramework.Binding.UnitTests/Test_IMaaToolkit.cs b/src/MaaFramework.Binding.UnitTests/Test_IMaaToolkit.cs index a6de2da..33bbb88 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_IMaaToolkit.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_IMaaToolkit.cs @@ -12,7 +12,7 @@ public class Test_IMaaToolkit public static Dictionary NewData => new() { #if MAA_NATIVE - { MaaTypes.Native, new MaaToolkit() }, + { MaaTypes.Native, MaaToolkit.Shared }, #endif }; public static Dictionary Data { get; private set; } = default!; diff --git a/src/MaaFramework.Binding.UnitTests/Test_IMaaUtility.cs b/src/MaaFramework.Binding.UnitTests/Test_IMaaUtility.cs index d50a234..3cadf96 100644 --- a/src/MaaFramework.Binding.UnitTests/Test_IMaaUtility.cs +++ b/src/MaaFramework.Binding.UnitTests/Test_IMaaUtility.cs @@ -10,7 +10,7 @@ public class Test_IMaaMaaUtility public static Dictionary NewData => new() { #if MAA_NATIVE - { MaaTypes.Native, new MaaUtility() }, + { MaaTypes.Native, MaaUtility.Shared }, #endif }; public static Dictionary Data { get; private set; } = default!; diff --git a/src/MaaFramework.Binding.UnitTests/packages.lock.json b/src/MaaFramework.Binding.UnitTests/packages.lock.json index feecfca..5e33f5c 100644 --- a/src/MaaFramework.Binding.UnitTests/packages.lock.json +++ b/src/MaaFramework.Binding.UnitTests/packages.lock.json @@ -42,33 +42,33 @@ }, "Maa.Framework.Runtime.linux-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "xobEEAtdwH/TCtVVeqzyZwWpgmBj9/G+YKDhw8otumXFo6gzTFwwm917sc4La6LZfztolbhEP3HjHdkBXZAlnA==" + "resolved": "4.0.0", + "contentHash": "UO0WrFCkSAzW3CGj0N6ah+Znn4MTkd7CeWrdxJiSyRkRtjgIl2lPf67ZbbdYdCpXMF7PxQdwJaqo1A895kI/Qg==" }, "Maa.Framework.Runtime.linux-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "lezMomm+OM83YIIRMeuH4kxp1dkGzi9ufRhI8HNAmWd5mQGVScR75Gz55dZlGQ0UPmtwPP2PT26/4D92zN8Tow==" + "resolved": "4.0.0", + "contentHash": "DAhsxoDXPJN7A96gZTUAWnub92xDKtd8MXLx0mxipvBPRJ/Qw4wes2IKYididKkMNBj1XNiqQ3ENQAvjgm05Bw==" }, "Maa.Framework.Runtime.osx-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "fmsehoumgpe5Il2BGl8FrHczUiWr42qUJXYM/GagSW5MlB/hDlxGwA+Apmks8KerNpDAqv1NsuPXRQxnOuvMpw==" + "resolved": "4.0.0", + "contentHash": "yYMbg9TRzlpe9YB96fT1oTpWcX7Yg7dNGjmk7mfSZ+nm3ZRY95Uy7GJ3apk+kgCim89KEt8LsV5mmLgCNXAhpg==" }, "Maa.Framework.Runtime.osx-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "afAeMiMiBOvuQfgXaiOiF3NAtWWKpigybM6pdxpAXupK5lyBrwyMgxh6hgzpduD3D+ohzdf4a5sdWdxLbyrdxw==" + "resolved": "4.0.0", + "contentHash": "5SvGaS2CMXECIC0QVzzr9hPUZQscIHIn1nddr8d7zyISTokkXMwQvaZRSu6hAibECXIg44yiowFYPPnS7SvOnQ==" }, "Maa.Framework.Runtime.win-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "tl9tEzViM5vwmuLE1ozMP+YdVBK2A8E1RdXCqk4zXRoaYgLqH24V9NVjACDIKDE9MArv4Yqask0s3JMJick1dg==" + "resolved": "4.0.0", + "contentHash": "h2QLNIn2m7w2uzN1696n0v5HPyK+aR0DexyiCBbjYQTdOvfXC1V5QcP9boCf0VTrQMhN7Wr+qtCbbwb5qOiXJA==" }, "Maa.Framework.Runtime.win-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "RxHzvnyVer26AMJfyME+EWFf2TKK8Ka8a3fBJQMJGZgvK+g06MTxW5LbumQp4F5ylMJvHr/+SVwo9sxZObsUBg==" + "resolved": "4.0.0", + "contentHash": "KkP36yP1s03GOcTDnm9HscOzZa5U2IeMcfV4gEZ1cg/Yji7ynKKtV2mRIsZnpPs2deFuTL3Qn22uPr9C8mHIqw==" }, "Microsoft.ApplicationInsights": { "type": "Transitive", @@ -161,7 +161,7 @@ "type": "Project", "dependencies": { "Maa.Framework.Native": "[1.0.0-dev, )", - "Maa.Framework.Runtimes": "[3.0.4, )" + "Maa.Framework.Runtimes": "[4.0.0, )" } }, "Maa.Framework.Binding": { @@ -182,28 +182,28 @@ "Maa.Framework.Native": { "type": "Project", "dependencies": { - "Maa.AgentBinary": "[1.0.0, )", + "Maa.AgentBinary": "[1.1.0, )", "Maa.Framework.Binding.Native": "[1.0.0-dev, )" } }, "Maa.AgentBinary": { "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "SITxxo/h53R/WlhaaG6CK4qWGwmc6/fcPykCnXG3tIs2Mx4iS2Y4XfRWlCtwpMoP0lyanjl+ZvqMUQ4vEV9U7A==" }, "Maa.Framework.Runtimes": { "type": "CentralTransitive", - "requested": "[3.0.4, )", - "resolved": "3.0.4", - "contentHash": "F9As/LIRRxXvrkubxgHxExoxCqVzYkfo1Ph3kHYxCYXrdUAZVXESr3o99L+NPv2rUZ9VkupKeL+Xomk4hXCcVw==", + "requested": "[4.0.0, )", + "resolved": "4.0.0", + "contentHash": "hHYtVnknsGZJj22TO4gEfrqUlhq6BfF9DBIM1w0U0dv0mz4fzijawmZJ9QpRX0UldOXq7HN8TBC2lSLyz00FAA==", "dependencies": { - "Maa.Framework.Runtime.linux-arm64": "3.0.4", - "Maa.Framework.Runtime.linux-x64": "3.0.4", - "Maa.Framework.Runtime.osx-arm64": "3.0.4", - "Maa.Framework.Runtime.osx-x64": "3.0.4", - "Maa.Framework.Runtime.win-arm64": "3.0.4", - "Maa.Framework.Runtime.win-x64": "3.0.4" + "Maa.Framework.Runtime.linux-arm64": "4.0.0", + "Maa.Framework.Runtime.linux-x64": "4.0.0", + "Maa.Framework.Runtime.osx-arm64": "4.0.0", + "Maa.Framework.Runtime.osx-x64": "4.0.0", + "Maa.Framework.Runtime.win-arm64": "4.0.0", + "Maa.Framework.Runtime.win-x64": "4.0.0" } } }, @@ -248,33 +248,33 @@ }, "Maa.Framework.Runtime.linux-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "xobEEAtdwH/TCtVVeqzyZwWpgmBj9/G+YKDhw8otumXFo6gzTFwwm917sc4La6LZfztolbhEP3HjHdkBXZAlnA==" + "resolved": "4.0.0", + "contentHash": "UO0WrFCkSAzW3CGj0N6ah+Znn4MTkd7CeWrdxJiSyRkRtjgIl2lPf67ZbbdYdCpXMF7PxQdwJaqo1A895kI/Qg==" }, "Maa.Framework.Runtime.linux-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "lezMomm+OM83YIIRMeuH4kxp1dkGzi9ufRhI8HNAmWd5mQGVScR75Gz55dZlGQ0UPmtwPP2PT26/4D92zN8Tow==" + "resolved": "4.0.0", + "contentHash": "DAhsxoDXPJN7A96gZTUAWnub92xDKtd8MXLx0mxipvBPRJ/Qw4wes2IKYididKkMNBj1XNiqQ3ENQAvjgm05Bw==" }, "Maa.Framework.Runtime.osx-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "fmsehoumgpe5Il2BGl8FrHczUiWr42qUJXYM/GagSW5MlB/hDlxGwA+Apmks8KerNpDAqv1NsuPXRQxnOuvMpw==" + "resolved": "4.0.0", + "contentHash": "yYMbg9TRzlpe9YB96fT1oTpWcX7Yg7dNGjmk7mfSZ+nm3ZRY95Uy7GJ3apk+kgCim89KEt8LsV5mmLgCNXAhpg==" }, "Maa.Framework.Runtime.osx-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "afAeMiMiBOvuQfgXaiOiF3NAtWWKpigybM6pdxpAXupK5lyBrwyMgxh6hgzpduD3D+ohzdf4a5sdWdxLbyrdxw==" + "resolved": "4.0.0", + "contentHash": "5SvGaS2CMXECIC0QVzzr9hPUZQscIHIn1nddr8d7zyISTokkXMwQvaZRSu6hAibECXIg44yiowFYPPnS7SvOnQ==" }, "Maa.Framework.Runtime.win-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "tl9tEzViM5vwmuLE1ozMP+YdVBK2A8E1RdXCqk4zXRoaYgLqH24V9NVjACDIKDE9MArv4Yqask0s3JMJick1dg==" + "resolved": "4.0.0", + "contentHash": "h2QLNIn2m7w2uzN1696n0v5HPyK+aR0DexyiCBbjYQTdOvfXC1V5QcP9boCf0VTrQMhN7Wr+qtCbbwb5qOiXJA==" }, "Maa.Framework.Runtime.win-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "RxHzvnyVer26AMJfyME+EWFf2TKK8Ka8a3fBJQMJGZgvK+g06MTxW5LbumQp4F5ylMJvHr/+SVwo9sxZObsUBg==" + "resolved": "4.0.0", + "contentHash": "KkP36yP1s03GOcTDnm9HscOzZa5U2IeMcfV4gEZ1cg/Yji7ynKKtV2mRIsZnpPs2deFuTL3Qn22uPr9C8mHIqw==" }, "Microsoft.ApplicationInsights": { "type": "Transitive", @@ -367,7 +367,7 @@ "type": "Project", "dependencies": { "Maa.Framework.Native": "[1.0.0-dev, )", - "Maa.Framework.Runtimes": "[3.0.4, )" + "Maa.Framework.Runtimes": "[4.0.0, )" } }, "Maa.Framework.Binding": { @@ -388,28 +388,28 @@ "Maa.Framework.Native": { "type": "Project", "dependencies": { - "Maa.AgentBinary": "[1.0.0, )", + "Maa.AgentBinary": "[1.1.0, )", "Maa.Framework.Binding.Native": "[1.0.0-dev, )" } }, "Maa.AgentBinary": { "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "SITxxo/h53R/WlhaaG6CK4qWGwmc6/fcPykCnXG3tIs2Mx4iS2Y4XfRWlCtwpMoP0lyanjl+ZvqMUQ4vEV9U7A==" }, "Maa.Framework.Runtimes": { "type": "CentralTransitive", - "requested": "[3.0.4, )", - "resolved": "3.0.4", - "contentHash": "F9As/LIRRxXvrkubxgHxExoxCqVzYkfo1Ph3kHYxCYXrdUAZVXESr3o99L+NPv2rUZ9VkupKeL+Xomk4hXCcVw==", + "requested": "[4.0.0, )", + "resolved": "4.0.0", + "contentHash": "hHYtVnknsGZJj22TO4gEfrqUlhq6BfF9DBIM1w0U0dv0mz4fzijawmZJ9QpRX0UldOXq7HN8TBC2lSLyz00FAA==", "dependencies": { - "Maa.Framework.Runtime.linux-arm64": "3.0.4", - "Maa.Framework.Runtime.linux-x64": "3.0.4", - "Maa.Framework.Runtime.osx-arm64": "3.0.4", - "Maa.Framework.Runtime.osx-x64": "3.0.4", - "Maa.Framework.Runtime.win-arm64": "3.0.4", - "Maa.Framework.Runtime.win-x64": "3.0.4" + "Maa.Framework.Runtime.linux-arm64": "4.0.0", + "Maa.Framework.Runtime.linux-x64": "4.0.0", + "Maa.Framework.Runtime.osx-arm64": "4.0.0", + "Maa.Framework.Runtime.osx-x64": "4.0.0", + "Maa.Framework.Runtime.win-arm64": "4.0.0", + "Maa.Framework.Runtime.win-x64": "4.0.0" } } } diff --git a/src/MaaFramework.Binding/Abstractions/IMaaDisposable.cs b/src/MaaFramework.Binding/Abstractions/IMaaDisposable.cs index 3f3720f..abde39f 100644 --- a/src/MaaFramework.Binding/Abstractions/IMaaDisposable.cs +++ b/src/MaaFramework.Binding/Abstractions/IMaaDisposable.cs @@ -11,9 +11,17 @@ public interface IMaaDisposable : IDisposable bool IsInvalid { get; } /// - /// Gets a value indicating whether an is thrown when current instance is invalid but still called. + /// Gets a value indicating whether an is thrown when the current instance is invalid but still called. /// bool ThrowOnInvalid { get; set; } + + /// + /// Gets a value indicating whether the current instance is stateless. + /// + /// + /// The lifetime of unmanaged resources is controlled by . + /// + bool IsStateless { get; } } // 设计思路: diff --git a/src/MaaFramework.Binding/Abstractions/MaaDisposableHandle.cs b/src/MaaFramework.Binding/Abstractions/MaaDisposableHandle.cs index 82e5bf8..71a96b2 100644 --- a/src/MaaFramework.Binding/Abstractions/MaaDisposableHandle.cs +++ b/src/MaaFramework.Binding/Abstractions/MaaDisposableHandle.cs @@ -45,6 +45,9 @@ public void SetHandleAsInvalid() /// public bool ThrowOnInvalid { get; set; } + /// + public bool IsStateless => !_needReleased; + /// /// Creates a instance. /// diff --git a/src/MaaFramework.Binding/Custom/IMaaCustomAction.cs b/src/MaaFramework.Binding/Custom/IMaaCustomAction.cs index 38942e5..cc8cf72 100644 --- a/src/MaaFramework.Binding/Custom/IMaaCustomAction.cs +++ b/src/MaaFramework.Binding/Custom/IMaaCustomAction.cs @@ -13,8 +13,9 @@ public interface IMaaCustomAction : IMaaCustomResource /// /// The context. /// The run args. + /// The run results. /// if the operation was executed successfully; otherwise, . - bool Run(in IMaaContext context, in RunArgs args); + bool Run(in IMaaContext context, in RunArgs args, in RunResults results); } /// @@ -27,3 +28,10 @@ public interface IMaaCustomAction : IMaaCustomResource /// Gets the recognition detail. /// Gets the recognition box. public sealed record RunArgs(string NodeName, TaskDetail TaskDetail, string ActionName, [StringSyntax("Json")] string ActionParam, RecognitionDetail RecognitionDetail, IMaaRectBuffer RecognitionBox); + +#pragma warning disable S2094 // Classes should not be empty +/// +/// The action run results. +/// +public sealed record RunResults; +#pragma warning restore S2094 // Classes should not be empty diff --git a/src/MaaFramework.Binding/Enums/Binding/ApiInfoFlags.cs b/src/MaaFramework.Binding/Enums/Binding/ApiInfoFlags.cs new file mode 100644 index 0000000..aed55a0 --- /dev/null +++ b/src/MaaFramework.Binding/Enums/Binding/ApiInfoFlags.cs @@ -0,0 +1,44 @@ +namespace MaaFramework.Binding; + +#pragma warning disable S2344 // Enumeration type names should not have "Flags" or "Enum" suffixes + +/// +/// Represents information about binding interoperable API. +/// +[Flags] +public enum ApiInfoFlags +{ + /// + /// No flags. + /// + None = 0, + + /// + /// Indicates that the API is in MaaFramework context. + /// + InFrameworkContext = 1, + + /// + /// Indicates that the API is in MaaAgentServer context. + /// + InAgentServerContext = 2, + + /// + /// Indicates that the API uses the default resolver. + /// + UseDefaultResolver = 1 << 8, + + /// + /// Indicates that the API uses the resolver from binding. + /// + UseBindingResolver = 2 << 8, +} + +internal static class ApiInfoFlagsExtensions +{ + internal const ApiInfoFlags ContextMask = ApiInfoFlags.InFrameworkContext | ApiInfoFlags.InAgentServerContext; + internal const ApiInfoFlags ResolverMask = ApiInfoFlags.UseDefaultResolver | ApiInfoFlags.UseBindingResolver; + + internal static bool HasFlag_Context(this ApiInfoFlags flags) => (flags & ContextMask) != ApiInfoFlags.None; + internal static bool HasFlag_ResolverExcept(this ApiInfoFlags flags, ApiInfoFlags other) => (flags & ~other & ResolverMask) != ApiInfoFlags.None; +} diff --git a/src/MaaFramework.Binding/Exceptions/MaaOperationException.cs b/src/MaaFramework.Binding/Exceptions/MaaOperationException.cs index d3d4710..6a0bd4e 100644 --- a/src/MaaFramework.Binding/Exceptions/MaaOperationException.cs +++ b/src/MaaFramework.Binding/Exceptions/MaaOperationException.cs @@ -11,12 +11,12 @@ public class MaaInteroperationException : MaaException /// /// Resource binding failed message. /// - public const string ResourceBindingFailedMessage = "MaaTasker failed to bind MaaResource."; + public const string ResourceBindingFailedMessage = "Failed to bind MaaResource."; /// /// Controller binding failed message. /// - public const string ControllerBindingFailedMessage = "MaaTasker failed to bind MaaController."; + public const string ControllerBindingFailedMessage = "Failed to bind MaaController."; /// /// Resource modified message. diff --git a/src/MaaFramework.Binding/Extensions/MaaOptionExtensions.cs b/src/MaaFramework.Binding/Extensions/MaaOptionExtensions.cs index e448004..f370ede 100644 --- a/src/MaaFramework.Binding/Extensions/MaaOptionExtensions.cs +++ b/src/MaaFramework.Binding/Extensions/MaaOptionExtensions.cs @@ -10,54 +10,54 @@ namespace MaaFramework.Binding; public static class MaaOptionExtensions { /// - public static bool SetOptionScreenshotTargetLongSide(this IMaaOption? opt, int value) + public static bool SetOption_ScreenshotTargetLongSide(this IMaaOption? opt, int value) => opt?.SetOption(ControllerOption.ScreenshotTargetLongSide, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionScreenshotTargetShortSide(this IMaaOption? opt, int value) + public static bool SetOption_ScreenshotTargetShortSide(this IMaaOption? opt, int value) => opt?.SetOption(ControllerOption.ScreenshotTargetShortSide, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionScreenshotUseRawSize(this IMaaOption? opt, bool value) + public static bool SetOption_ScreenshotUseRawSize(this IMaaOption? opt, bool value) => opt?.SetOption(ControllerOption.ScreenshotUseRawSize, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionRecording(this IMaaOption? opt, bool value) + public static bool SetOption_Recording(this IMaaOption? opt, bool value) => opt?.SetOption(ControllerOption.Recording, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionLogDir(this IMaaOption? opt, string value) + public static bool SetOption_LogDir(this IMaaOption? opt, string value) => opt?.SetOption(GlobalOption.LogDir, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionSaveDraw(this IMaaOption? opt, bool value) + public static bool SetOption_SaveDraw(this IMaaOption? opt, bool value) => opt?.SetOption(GlobalOption.SaveDraw, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionRecording(this IMaaOption? opt, bool value) + public static bool SetOption_Recording(this IMaaOption? opt, bool value) => opt?.SetOption(GlobalOption.Recording, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionStdoutLevel(this IMaaOption? opt, LoggingLevel value) + public static bool SetOption_StdoutLevel(this IMaaOption? opt, LoggingLevel value) => opt?.SetOption(GlobalOption.StdoutLevel, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionShowHitDraw(this IMaaOption? opt, bool value) + public static bool SetOption_ShowHitDraw(this IMaaOption? opt, bool value) => opt?.SetOption(GlobalOption.ShowHitDraw, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionDebugMode(this IMaaOption? opt, bool value) + public static bool SetOption_DebugMode(this IMaaOption? opt, bool value) => opt?.SetOption(GlobalOption.DebugMode, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionInferenceDevice(this IMaaOption? opt, InferenceDevice value) + public static bool SetOption_InferenceDevice(this IMaaOption? opt, InferenceDevice value) => opt?.SetOption(ResourceOption.InferenceDevice, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionInferenceDevice(this IMaaOption? opt, int value) + public static bool SetOption_InferenceDevice(this IMaaOption? opt, int value) => opt?.SetOption(ResourceOption.InferenceDevice, value) ?? throw new ArgumentNullException(nameof(opt)); /// - public static bool SetOptionInferenceDevice(this IMaaOption? opt, InferenceExecutionProvider value) + public static bool SetOption_InferenceExecutionProvider(this IMaaOption? opt, InferenceExecutionProvider value) => opt?.SetOption(ResourceOption.InferenceExecutionProvider, value) ?? throw new ArgumentNullException(nameof(opt)); } diff --git a/src/MaaFramework.Binding/IMaaAgentClient.cs b/src/MaaFramework.Binding/IMaaAgentClient.cs new file mode 100644 index 0000000..9f9595d --- /dev/null +++ b/src/MaaFramework.Binding/IMaaAgentClient.cs @@ -0,0 +1,92 @@ +using MaaFramework.Binding.Abstractions; +using System.Diagnostics; + +namespace MaaFramework.Binding; + +/// +/// An interface defining wrapped members for MaaAgentClient with generic handle. +/// +/// The type of handle. +public interface IMaaAgentClient : IMaaAgentClient, IMaaDisposableHandle; + +/// +/// An interface defining wrapped members for MaaAgentClient. +/// +public interface IMaaAgentClient : IMaaDisposable +{ + /// + /// Gets the unique identifier used to communicate with the agent server. + /// + string Id { get; } + + /// + /// Gets or sets a resource that binds to the . + /// + /// + /// + IMaaResource Resource { get; set; } + + /// + /// Starts the connection. + /// + /// if the connection was started successfully; otherwise, . + bool LinkStart(); + + /// + /// Starts the agent server process using the specified and connects to the agent server. + /// To start a new process, the current must have exited first. + /// + /// The process start info. + /// An optional token to cancel the asynchronous operation waiting for the connection. + /// if the connection was started successfully; otherwise, . + /// The has had cancellation requested. + bool LinkStart(ProcessStartInfo info, CancellationToken cancellationToken = default); + + /// + /// Starts the agent server process using the specified method and connects to the agent server. + /// To start a new process, the current must have exited first. + /// + /// The delegate method that defines how to start the agent server process. + /// An optional token to cancel the asynchronous operation waiting for the connection. + /// if the connection was started successfully; otherwise, . + /// The has had cancellation requested. + bool LinkStart(AgentServerStartupMethod method, CancellationToken cancellationToken = default); + + /// + /// Starts the connection asynchronously unless the process has exited. + /// + /// The process to monitor for exit status. + /// An optional token to cancel the asynchronous operation waiting for the connection. + /// + /// A task that represents the asynchronous operation. The task result contains + /// if the connection was started successfully; otherwise, . + /// + /// The has had cancellation requested. + Task LinkStartUnlessProcessExit(Process process, CancellationToken cancellationToken); + + /// + /// Stops the connection. + /// + /// if the connection was stopped successfully; otherwise, . + bool LinkStop(); + + /// + /// Represents a method that starts the agent server process. + /// + /// The unique identifier used to communicate with the agent server. + /// The directory path where the native assemblies are located. + /// + /// A new that is associated with the process resource, or if no process resource is started. + /// + /// + /// The implementation of this delegate is responsible for validating the provided parameters. + /// Ensure that and are valid and meet the requirements of the agent server process. + /// + delegate Process? AgentServerStartupMethod(string identifier, string nativeAssemblyDirectory); + + /// + /// Gets the agent server process managed by from method LinkStart. + /// + /// The process is unavailable or not managed by . + Process AgentServerProcess { get; } +} diff --git a/src/MaaFramework.Binding/IMaaAgentServer.cs b/src/MaaFramework.Binding/IMaaAgentServer.cs new file mode 100644 index 0000000..5f73052 --- /dev/null +++ b/src/MaaFramework.Binding/IMaaAgentServer.cs @@ -0,0 +1,48 @@ +using MaaFramework.Binding.Custom; + +namespace MaaFramework.Binding; + +/// +/// An interface defining wrapped members for MaaAgentServer. +/// +public interface IMaaAgentServer +{ + /// + /// Configures the unique identifier used to communicate with the agent client. + /// + /// The unique identifier used to communicate with the agent client. + IMaaAgentServer WithIdentifier(string identifier); + + /// + /// Registers a or in the . + /// + /// The or . + /// The new name that will be used to reference the custom resource. + /// The custom resource instance to register. + /// Thrown if the registration fails. + IMaaAgentServer Register(string name, T custom) where T : IMaaCustomResource; + + /// + IMaaAgentServer Register(T custom) where T : IMaaCustomResource; + + /// + /// Starts up the agent server to prepare for receiving client messages from the specified connection. + /// + /// Thrown if the registration fails. + IMaaAgentServer StartUp(); + + /// + /// Shuts down the agent server. + /// + IMaaAgentServer ShutDown(); + + /// + /// Blocks the calling thread until the thread for receiving client messages finishes its execution. + /// + IMaaAgentServer Join(); + + /// + /// Separates the thread for receiving client messages, allowing execution to continue independently. + /// + IMaaAgentServer Detach(); +} diff --git a/src/MaaFramework.Binding/IMaaContext.cs b/src/MaaFramework.Binding/IMaaContext.cs index 4f0779c..a413f9d 100644 --- a/src/MaaFramework.Binding/IMaaContext.cs +++ b/src/MaaFramework.Binding/IMaaContext.cs @@ -26,28 +26,28 @@ public interface IMaaContext : ICloneable /// The entry name of the task. /// The json used to override the pipeline. /// if the operation was executed successfully; otherwise, . - TaskDetail? RunTask(string entry, [StringSyntax("Json")] string pipelineOverride); + TaskDetail? RunTask(string entry, [StringSyntax("Json")] string pipelineOverride = "{}"); /// /// Run a recognition. /// /// The recognition entry name. - /// The json used to override the pipeline. /// The image to be recognized. + /// The json used to override the pipeline. /// if the operation was executed successfully; otherwise, . /// - RecognitionDetail? RunRecognition(string entry, [StringSyntax("Json")] string pipelineOverride, IMaaImageBuffer image); + RecognitionDetail? RunRecognition(string entry, IMaaImageBuffer image, [StringSyntax("Json")] string pipelineOverride = "{}"); /// /// Run an action. /// /// The action entry name. - /// The json used to override the pipeline. /// The rect buffer containing current rect in the recognition result. /// The rect detail in the recognition result. + /// The json used to override the pipeline. /// if the operation was executed successfully; otherwise, . /// - NodeDetail? RunAction(string entry, [StringSyntax("Json")] string pipelineOverride, IMaaRectBuffer recognitionBox, string recognitionDetail); + NodeDetail? RunAction(string entry, IMaaRectBuffer recognitionBox, [StringSyntax("Json")] string recognitionDetail, [StringSyntax("Json")] string pipelineOverride = "{}"); /// /// Override a pipeline. diff --git a/src/MaaFramework.Binding/IMaaResource.cs b/src/MaaFramework.Binding/IMaaResource.cs index 3e21b3e..b784619 100644 --- a/src/MaaFramework.Binding/IMaaResource.cs +++ b/src/MaaFramework.Binding/IMaaResource.cs @@ -18,9 +18,9 @@ public interface IMaaResource : IMaaCommon, IMaaOption, IMaaPost /// Registers a or in the . /// /// The or . - /// The new name that will be used to reference it. - /// The or . - /// if the custom action or recognition was registered successfully; otherwise, . + /// The new name that will be used to reference the custom resource. + /// The custom resource instance to register. + /// if the registration was successful; otherwise, . bool Register(string name, T custom) where T : IMaaCustomResource; /// @@ -30,24 +30,25 @@ public interface IMaaResource : IMaaCommon, IMaaOption, IMaaPost /// Unregisters a or in the . /// /// The or . - /// The name of or when it was registered. - /// if the custom action or recognition was unregistered successfully; otherwise, . + /// The name of the instance when it was registered. + /// if the unregistration was successful; otherwise, . bool Unregister(string name) where T : IMaaCustomResource; /// - /// The or . + /// The custom resource instance to unregister. bool Unregister(T custom) where T : IMaaCustomResource; /// /// Clears all or registered in the . /// /// The or . - /// if custom actions or recognitions were cleared successfully; otherwise, . + /// if custom resource instances were cleared successfully; otherwise, . bool Clear() where T : IMaaCustomResource; /// - /// Clear the loaded resource. + /// Clears the loaded resource. /// + /// Whether to include custom resources. /// if the is cleared successfully; otherwise, . bool Clear(bool includeCustomResource = false); diff --git a/src/MaaFramework.Binding/MaaFramework.Binding.csproj b/src/MaaFramework.Binding/MaaFramework.Binding.csproj index 8a40f6b..a32697b 100644 --- a/src/MaaFramework.Binding/MaaFramework.Binding.csproj +++ b/src/MaaFramework.Binding/MaaFramework.Binding.csproj @@ -12,4 +12,8 @@ snupkg + + + + diff --git a/src/MaaFramework.Binding/MaaImage.cs b/src/MaaFramework.Binding/MaaImage.cs index 17e287a..d3ea0fd 100644 --- a/src/MaaFramework.Binding/MaaImage.cs +++ b/src/MaaFramework.Binding/MaaImage.cs @@ -25,6 +25,9 @@ public bool ThrowOnInvalid set => buffer.ThrowOnInvalid = value; } + /// + public bool IsStateless => buffer.IsStateless; + /// /// Caches the image data from the . /// diff --git a/src/MaaFramework.Binding/MaaMsg.cs b/src/MaaFramework.Binding/MaaMsg.cs index 9642a42..3e0d8ca 100644 --- a/src/MaaFramework.Binding/MaaMsg.cs +++ b/src/MaaFramework.Binding/MaaMsg.cs @@ -12,7 +12,7 @@ namespace MaaFramework.Binding.Notification; -//MaaApiDocument Version: (main) v3.0.4 +//MaaApiDocument Version: (main) v4.0.0 /// /// A callback consists of a message and a payload. /// The message is a string that indicates the type of the message. diff --git a/src/MaaFramework.Native/packages.lock.json b/src/MaaFramework.Native/packages.lock.json index 40fc620..1932700 100644 --- a/src/MaaFramework.Native/packages.lock.json +++ b/src/MaaFramework.Native/packages.lock.json @@ -4,9 +4,9 @@ "net7.0": { "Maa.AgentBinary": { "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "SITxxo/h53R/WlhaaG6CK4qWGwmc6/fcPykCnXG3tIs2Mx4iS2Y4XfRWlCtwpMoP0lyanjl+ZvqMUQ4vEV9U7A==" }, "SonarAnalyzer.CSharp": { "type": "Direct", @@ -27,9 +27,9 @@ "net9.0": { "Maa.AgentBinary": { "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "SITxxo/h53R/WlhaaG6CK4qWGwmc6/fcPykCnXG3tIs2Mx4iS2Y4XfRWlCtwpMoP0lyanjl+ZvqMUQ4vEV9U7A==" }, "SonarAnalyzer.CSharp": { "type": "Direct", diff --git a/src/MaaFramework/packages.lock.json b/src/MaaFramework/packages.lock.json index 38658bb..fb372b1 100644 --- a/src/MaaFramework/packages.lock.json +++ b/src/MaaFramework/packages.lock.json @@ -4,16 +4,16 @@ "net7.0": { "Maa.Framework.Runtimes": { "type": "Direct", - "requested": "[3.0.4, )", - "resolved": "3.0.4", - "contentHash": "F9As/LIRRxXvrkubxgHxExoxCqVzYkfo1Ph3kHYxCYXrdUAZVXESr3o99L+NPv2rUZ9VkupKeL+Xomk4hXCcVw==", + "requested": "[4.0.0, )", + "resolved": "4.0.0", + "contentHash": "hHYtVnknsGZJj22TO4gEfrqUlhq6BfF9DBIM1w0U0dv0mz4fzijawmZJ9QpRX0UldOXq7HN8TBC2lSLyz00FAA==", "dependencies": { - "Maa.Framework.Runtime.linux-arm64": "3.0.4", - "Maa.Framework.Runtime.linux-x64": "3.0.4", - "Maa.Framework.Runtime.osx-arm64": "3.0.4", - "Maa.Framework.Runtime.osx-x64": "3.0.4", - "Maa.Framework.Runtime.win-arm64": "3.0.4", - "Maa.Framework.Runtime.win-x64": "3.0.4" + "Maa.Framework.Runtime.linux-arm64": "4.0.0", + "Maa.Framework.Runtime.linux-x64": "4.0.0", + "Maa.Framework.Runtime.osx-arm64": "4.0.0", + "Maa.Framework.Runtime.osx-x64": "4.0.0", + "Maa.Framework.Runtime.win-arm64": "4.0.0", + "Maa.Framework.Runtime.win-x64": "4.0.0" } }, "SonarAnalyzer.CSharp": { @@ -24,33 +24,33 @@ }, "Maa.Framework.Runtime.linux-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "xobEEAtdwH/TCtVVeqzyZwWpgmBj9/G+YKDhw8otumXFo6gzTFwwm917sc4La6LZfztolbhEP3HjHdkBXZAlnA==" + "resolved": "4.0.0", + "contentHash": "UO0WrFCkSAzW3CGj0N6ah+Znn4MTkd7CeWrdxJiSyRkRtjgIl2lPf67ZbbdYdCpXMF7PxQdwJaqo1A895kI/Qg==" }, "Maa.Framework.Runtime.linux-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "lezMomm+OM83YIIRMeuH4kxp1dkGzi9ufRhI8HNAmWd5mQGVScR75Gz55dZlGQ0UPmtwPP2PT26/4D92zN8Tow==" + "resolved": "4.0.0", + "contentHash": "DAhsxoDXPJN7A96gZTUAWnub92xDKtd8MXLx0mxipvBPRJ/Qw4wes2IKYididKkMNBj1XNiqQ3ENQAvjgm05Bw==" }, "Maa.Framework.Runtime.osx-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "fmsehoumgpe5Il2BGl8FrHczUiWr42qUJXYM/GagSW5MlB/hDlxGwA+Apmks8KerNpDAqv1NsuPXRQxnOuvMpw==" + "resolved": "4.0.0", + "contentHash": "yYMbg9TRzlpe9YB96fT1oTpWcX7Yg7dNGjmk7mfSZ+nm3ZRY95Uy7GJ3apk+kgCim89KEt8LsV5mmLgCNXAhpg==" }, "Maa.Framework.Runtime.osx-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "afAeMiMiBOvuQfgXaiOiF3NAtWWKpigybM6pdxpAXupK5lyBrwyMgxh6hgzpduD3D+ohzdf4a5sdWdxLbyrdxw==" + "resolved": "4.0.0", + "contentHash": "5SvGaS2CMXECIC0QVzzr9hPUZQscIHIn1nddr8d7zyISTokkXMwQvaZRSu6hAibECXIg44yiowFYPPnS7SvOnQ==" }, "Maa.Framework.Runtime.win-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "tl9tEzViM5vwmuLE1ozMP+YdVBK2A8E1RdXCqk4zXRoaYgLqH24V9NVjACDIKDE9MArv4Yqask0s3JMJick1dg==" + "resolved": "4.0.0", + "contentHash": "h2QLNIn2m7w2uzN1696n0v5HPyK+aR0DexyiCBbjYQTdOvfXC1V5QcP9boCf0VTrQMhN7Wr+qtCbbwb5qOiXJA==" }, "Maa.Framework.Runtime.win-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "RxHzvnyVer26AMJfyME+EWFf2TKK8Ka8a3fBJQMJGZgvK+g06MTxW5LbumQp4F5ylMJvHr/+SVwo9sxZObsUBg==" + "resolved": "4.0.0", + "contentHash": "KkP36yP1s03GOcTDnm9HscOzZa5U2IeMcfV4gEZ1cg/Yji7ynKKtV2mRIsZnpPs2deFuTL3Qn22uPr9C8mHIqw==" }, "Maa.Framework.Binding": { "type": "Project" @@ -64,30 +64,30 @@ "Maa.Framework.Native": { "type": "Project", "dependencies": { - "Maa.AgentBinary": "[1.0.0, )", + "Maa.AgentBinary": "[1.1.0, )", "Maa.Framework.Binding.Native": "[1.0.0-dev, )" } }, "Maa.AgentBinary": { "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "SITxxo/h53R/WlhaaG6CK4qWGwmc6/fcPykCnXG3tIs2Mx4iS2Y4XfRWlCtwpMoP0lyanjl+ZvqMUQ4vEV9U7A==" } }, "net9.0": { "Maa.Framework.Runtimes": { "type": "Direct", - "requested": "[3.0.4, )", - "resolved": "3.0.4", - "contentHash": "F9As/LIRRxXvrkubxgHxExoxCqVzYkfo1Ph3kHYxCYXrdUAZVXESr3o99L+NPv2rUZ9VkupKeL+Xomk4hXCcVw==", + "requested": "[4.0.0, )", + "resolved": "4.0.0", + "contentHash": "hHYtVnknsGZJj22TO4gEfrqUlhq6BfF9DBIM1w0U0dv0mz4fzijawmZJ9QpRX0UldOXq7HN8TBC2lSLyz00FAA==", "dependencies": { - "Maa.Framework.Runtime.linux-arm64": "3.0.4", - "Maa.Framework.Runtime.linux-x64": "3.0.4", - "Maa.Framework.Runtime.osx-arm64": "3.0.4", - "Maa.Framework.Runtime.osx-x64": "3.0.4", - "Maa.Framework.Runtime.win-arm64": "3.0.4", - "Maa.Framework.Runtime.win-x64": "3.0.4" + "Maa.Framework.Runtime.linux-arm64": "4.0.0", + "Maa.Framework.Runtime.linux-x64": "4.0.0", + "Maa.Framework.Runtime.osx-arm64": "4.0.0", + "Maa.Framework.Runtime.osx-x64": "4.0.0", + "Maa.Framework.Runtime.win-arm64": "4.0.0", + "Maa.Framework.Runtime.win-x64": "4.0.0" } }, "SonarAnalyzer.CSharp": { @@ -98,33 +98,33 @@ }, "Maa.Framework.Runtime.linux-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "xobEEAtdwH/TCtVVeqzyZwWpgmBj9/G+YKDhw8otumXFo6gzTFwwm917sc4La6LZfztolbhEP3HjHdkBXZAlnA==" + "resolved": "4.0.0", + "contentHash": "UO0WrFCkSAzW3CGj0N6ah+Znn4MTkd7CeWrdxJiSyRkRtjgIl2lPf67ZbbdYdCpXMF7PxQdwJaqo1A895kI/Qg==" }, "Maa.Framework.Runtime.linux-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "lezMomm+OM83YIIRMeuH4kxp1dkGzi9ufRhI8HNAmWd5mQGVScR75Gz55dZlGQ0UPmtwPP2PT26/4D92zN8Tow==" + "resolved": "4.0.0", + "contentHash": "DAhsxoDXPJN7A96gZTUAWnub92xDKtd8MXLx0mxipvBPRJ/Qw4wes2IKYididKkMNBj1XNiqQ3ENQAvjgm05Bw==" }, "Maa.Framework.Runtime.osx-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "fmsehoumgpe5Il2BGl8FrHczUiWr42qUJXYM/GagSW5MlB/hDlxGwA+Apmks8KerNpDAqv1NsuPXRQxnOuvMpw==" + "resolved": "4.0.0", + "contentHash": "yYMbg9TRzlpe9YB96fT1oTpWcX7Yg7dNGjmk7mfSZ+nm3ZRY95Uy7GJ3apk+kgCim89KEt8LsV5mmLgCNXAhpg==" }, "Maa.Framework.Runtime.osx-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "afAeMiMiBOvuQfgXaiOiF3NAtWWKpigybM6pdxpAXupK5lyBrwyMgxh6hgzpduD3D+ohzdf4a5sdWdxLbyrdxw==" + "resolved": "4.0.0", + "contentHash": "5SvGaS2CMXECIC0QVzzr9hPUZQscIHIn1nddr8d7zyISTokkXMwQvaZRSu6hAibECXIg44yiowFYPPnS7SvOnQ==" }, "Maa.Framework.Runtime.win-arm64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "tl9tEzViM5vwmuLE1ozMP+YdVBK2A8E1RdXCqk4zXRoaYgLqH24V9NVjACDIKDE9MArv4Yqask0s3JMJick1dg==" + "resolved": "4.0.0", + "contentHash": "h2QLNIn2m7w2uzN1696n0v5HPyK+aR0DexyiCBbjYQTdOvfXC1V5QcP9boCf0VTrQMhN7Wr+qtCbbwb5qOiXJA==" }, "Maa.Framework.Runtime.win-x64": { "type": "Transitive", - "resolved": "3.0.4", - "contentHash": "RxHzvnyVer26AMJfyME+EWFf2TKK8Ka8a3fBJQMJGZgvK+g06MTxW5LbumQp4F5ylMJvHr/+SVwo9sxZObsUBg==" + "resolved": "4.0.0", + "contentHash": "KkP36yP1s03GOcTDnm9HscOzZa5U2IeMcfV4gEZ1cg/Yji7ynKKtV2mRIsZnpPs2deFuTL3Qn22uPr9C8mHIqw==" }, "Maa.Framework.Binding": { "type": "Project" @@ -138,15 +138,15 @@ "Maa.Framework.Native": { "type": "Project", "dependencies": { - "Maa.AgentBinary": "[1.0.0, )", + "Maa.AgentBinary": "[1.1.0, )", "Maa.Framework.Binding.Native": "[1.0.0-dev, )" } }, "Maa.AgentBinary": { "type": "CentralTransitive", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "SITxxo/h53R/WlhaaG6CK4qWGwmc6/fcPykCnXG3tIs2Mx4iS2Y4XfRWlCtwpMoP0lyanjl+ZvqMUQ4vEV9U7A==" } } } diff --git a/tools/Builder/Build.csx b/tools/Builder/Build.csx index 163158b..cf035f3 100644 --- a/tools/Builder/Build.csx +++ b/tools/Builder/Build.csx @@ -31,7 +31,7 @@ var version = tags.Count switch }; var runtimes = NuGetVersion.Parse( - XDocument.Load("Directory.Packages.props") + XDocument.Load("./src/Directory.Packages.props") .Descendants("PackageVersion") .FirstOrDefault(e => e.Attribute("Include")?.Value == "Maa.Framework.Runtimes") !.Attribute("Version")