diff --git a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs b/src/Ryujinx.HLE.Generators/UserServiceGenerator.cs similarity index 50% rename from src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs rename to src/Ryujinx.HLE.Generators/UserServiceGenerator.cs index a5c8e9c5f..ace720667 100644 --- a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs +++ b/src/Ryujinx.HLE.Generators/UserServiceGenerator.cs @@ -1,19 +1,29 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; using System.Linq; namespace Ryujinx.HLE.Generators { [Generator] - public sealed class IpcServiceGenerator : IIncrementalGenerator + public sealed class UserServiceGenerator : IIncrementalGenerator { - private sealed record ServiceData + private sealed class ServiceData : IEquatable { public required string FullName { get; init; } - public required bool HasOneParamCtor { get; init; } - public required bool HasTwoParamCtor { get; init; } - public required string SecondParamTypeFullName { get; init; } + public required IReadOnlyList<(string ServiceName, string ParameterValue)> Instances { get; init; } + + public override bool Equals(object obj) + => obj is ServiceData data && Equals(data); + + public bool Equals(ServiceData other) + { + return this.FullName == other.FullName && this.Instances.SequenceEqual(other.Instances); + } + + public override int GetHashCode() => FullName.GetHashCode(); } public void Initialize(IncrementalGeneratorInitializationContext context) @@ -23,17 +33,18 @@ namespace Ryujinx.HLE.Generators transform: (ctx, _) => { var target = (INamedTypeSymbol)ctx.TargetSymbol; - var twoParamCtor = target.Constructors.FirstOrDefault(ctor => ctor.Parameters.Length == 2); + var instances = ctx.Attributes.Select(attr => + { + string param = attr.ConstructorArguments is [_, { IsNull: false } arg] ? arg.ToCSharpString() : null; + return ((string)attr.ConstructorArguments[0].Value, param); + }); return new ServiceData { FullName = target.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), - HasOneParamCtor = target.Constructors.Any(ctor => ctor.Parameters.Length == 1), - HasTwoParamCtor = twoParamCtor != null, - SecondParamTypeFullName = twoParamCtor?.Parameters[1].Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), + Instances = instances.ToList(), }; } - ) - .Where(data => data.HasOneParamCtor || data.HasTwoParamCtor); + ); context.RegisterSourceOutput(pipeline.Collect(), (ctx, data) => @@ -45,25 +56,29 @@ namespace Ryujinx.HLE.Generators generator.EnterScope("namespace Ryujinx.HLE.HOS.Services.Sm"); generator.EnterScope("partial class IUserInterface"); - generator.EnterScope("public IpcService? GetServiceInstance(Type type, ServiceCtx context, object? parameter = null)"); + generator.EnterScope("public IpcService? GetServiceInstance(string name, ServiceCtx context)"); + + generator.EnterScope("return name switch"); - foreach (var service in data) + foreach (var serviceImpl in data) { - generator.EnterScope($"if (type == typeof({service.FullName}))"); - if (service.HasTwoParamCtor) + foreach (var instance in serviceImpl.Instances) { - generator.EnterScope("if (parameter != null)"); - generator.AppendLine($"return new {service.FullName}(context, ({service.SecondParamTypeFullName})parameter);"); - generator.LeaveScope(); + if (instance.ParameterValue == null) + { + generator.AppendLine($"\"{instance.ServiceName}\" => new {serviceImpl.FullName}(context),"); + } + else + { + generator.AppendLine($"\"{instance.ServiceName}\" => new {serviceImpl.FullName}(context, {instance.ParameterValue}),"); + } } - if (service.HasOneParamCtor) - { - generator.AppendLine($"return new {service.FullName}(context);"); - } - generator.LeaveScope(); } - generator.AppendLine("return null;"); + generator.AppendLine("_ => null,"); + + generator.LeaveScope(";"); + generator.LeaveScope(); generator.LeaveScope(); diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs index b88815778..3f2832ef2 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/IBaasAccessTokenAccessor.cs @@ -3,6 +3,6 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc [Service("acc:aa", AccountServiceFlag.BaasAccessTokenAccessor)] // Max Sessions: 4 class IBaasAccessTokenAccessor : IpcService { - public IBaasAccessTokenAccessor(ServiceCtx context) { } + public IBaasAccessTokenAccessor(ServiceCtx context, AccountServiceFlag serviceFlag) { } } } diff --git a/src/Ryujinx.HLE/HOS/Services/IpcService.cs b/src/Ryujinx.HLE/HOS/Services/IpcService.cs index c7dee64fb..87e9d7b59 100644 --- a/src/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/src/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -11,8 +11,9 @@ using System.Reflection; namespace Ryujinx.HLE.HOS.Services { - abstract class IpcService + abstract partial class IpcService { + public IReadOnlyDictionary CmifCommands { get; } public IReadOnlyDictionary TipcCommands { get; } diff --git a/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs index f19eeebfc..743c208e4 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs @@ -4,18 +4,13 @@ using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Ipc; using Ryujinx.Horizon.Common; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Reflection; using System.Text; namespace Ryujinx.HLE.HOS.Services.Sm { partial class IUserInterface : IpcService { - private static readonly Dictionary _services; - private readonly SmRegistry _registry; private readonly ServerBase _commonServer; @@ -27,14 +22,6 @@ namespace Ryujinx.HLE.HOS.Services.Sm _registry = registry; } - static IUserInterface() - { - _services = typeof(IUserInterface).Assembly.GetTypes() - .SelectMany(type => type.GetCustomAttributes(typeof(ServiceAttribute), true) - .Select(service => (((ServiceAttribute)service).Name, type))) - .ToDictionary(service => service.Name, service => service.type); - } - [CommandCmif(0)] [CommandTipc(0)] // 12.0.0+ // Initialize(pid, u64 reserved) @@ -91,12 +78,8 @@ namespace Ryujinx.HLE.HOS.Services.Sm } else { - if (_services.TryGetValue(name, out Type type)) + if (GetServiceInstance(name, context) is { } service) { - ServiceAttribute serviceAttribute = type.GetCustomAttributes().First(service => service.Name == name); - - IpcService service = GetServiceInstance(type, context, serviceAttribute.Parameter); - service.TrySetServer(_commonServer); service.Server.AddSessionObj(session.ServerSession, service); }