From eb7fa55656ac954cd3ab528aac384a4a12261b53 Mon Sep 17 00:00:00 2001 From: cneicy Date: Sat, 5 Sep 2026 02:34:04 +0800 Subject: [PATCH] feat: add shared runtime and codegen support --- CodeGen/Editor/NetworkEventILPostProcessor.cs | 174 +----------------- ...nity.ShrinkNetwork.EventBus.CodeGen.asmdef | 3 +- ShrinkNetwork.Integration.EventBus.asmdef | 1 + ShrinkNetworkEventBusBridge.cs | 20 +- package.json | 10 +- 5 files changed, 26 insertions(+), 182 deletions(-) diff --git a/CodeGen/Editor/NetworkEventILPostProcessor.cs b/CodeGen/Editor/NetworkEventILPostProcessor.cs index 1d40d61..6cf8e60 100644 --- a/CodeGen/Editor/NetworkEventILPostProcessor.cs +++ b/CodeGen/Editor/NetworkEventILPostProcessor.cs @@ -1,13 +1,7 @@ #nullable enable -using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Pdb; -using ShrinkEventBus.CodeGen; +using ShrinkShared.CodeGen; using Unity.CompilationPipeline.Common.Diagnostics; using Unity.CompilationPipeline.Common.ILPostProcessing; @@ -15,170 +9,14 @@ namespace ShrinkNetwork.Integration.CodeGen { public sealed class NetworkEventILPostProcessor : ILPostProcessor { - private const string IntegrationAssembly = "ShrinkNetwork.Integration.EventBus"; - public override ILPostProcessor GetInstance() => this; public override bool WillProcess(ICompiledAssembly compiledAssembly) => - compiledAssembly.References.Any(reference => - string.Equals(Path.GetFileNameWithoutExtension(reference), IntegrationAssembly, - StringComparison.Ordinal)); + UnityShrinkCodeGenAdapter.ReferencesAny(compiledAssembly, "ShrinkNetwork.Integration.EventBus"); - public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) - { - var diagnostics = new List(); - if (!WillProcess(compiledAssembly)) - return new ILPostProcessResult(compiledAssembly.InMemoryAssembly, diagnostics); - - var assembly = ReadAssembly(compiledAssembly); - try - { - InjectRegistrations(assembly.MainModule); - } - catch (Exception exception) - { - diagnostics.Add(new DiagnosticMessage - { - DiagnosticType = DiagnosticType.Error, - MessageData = $"[ShrinkNetwork.EventBus.CodeGen] {exception.Message}" - }); - } - return WriteAssembly(assembly, diagnostics); - } - - private static void InjectRegistrations(ModuleDefinition module) - { - var networkEventAttribute = ResolveType(module, - "ShrinkNetwork.Integration.ShrinkNetworkEventAttribute", IntegrationAssembly); - var messageAttribute = ResolveType(module, - "ShrinkNetwork.ShrinkNetworkMessageAttribute", "ShrinkNetwork.Runtime"); - var registryType = ResolveType(module, - "ShrinkNetwork.Integration.ShrinkNetworkEventRegistry", IntegrationAssembly); - if (networkEventAttribute == null || messageAttribute == null || registryType == null) - return; - - var registrations = GetAllTypes(module.Types) - .Where(type => !type.IsAbstract && HasAttribute(type, networkEventAttribute)) - .Select(type => new - { - Type = type, - Message = type.CustomAttributes.FirstOrDefault(attribute => - attribute.AttributeType.FullName == messageAttribute.FullName) - }) - .Where(item => item.Message != null) - .ToArray(); - if (registrations.Length == 0) - return; - - var registerDefinition = registryType.Resolve()?.Methods.Single(method => - method.Name == "Register" && method.HasGenericParameters) - ?? throw new InvalidOperationException("ShrinkNetworkEventRegistry.Register was not found."); - var registerOpen = module.ImportReference(registerDefinition); - - var bootstrap = new TypeDefinition("ShrinkNetwork.Integration.Generated", - "ShrinkGeneratedNetworkEventBindings", - TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic, - module.TypeSystem.Object); - module.Types.Add(bootstrap); - var initialize = new MethodDefinition("Register", - MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig, - module.TypeSystem.Void); - bootstrap.Methods.Add(initialize); - var il = initialize.Body.GetILProcessor(); - - foreach (var item in registrations) - { - var attribute = item.Message!; - if (attribute.ConstructorArguments.Count == 0) - throw new InvalidOperationException( - $"[ShrinkNetworkMessage] on {item.Type.FullName} has no opcode."); - - var opcode = Convert.ToInt32(attribute.ConstructorArguments[0].Value); - var route = attribute.ConstructorArguments.Count > 1 - ? attribute.ConstructorArguments[1].Value as string - : null; - var registerClosed = new GenericInstanceMethod(registerOpen); - registerClosed.GenericArguments.Add(module.ImportReference(item.Type)); - il.Emit(OpCodes.Ldc_I4, opcode); - if (route == null) - il.Emit(OpCodes.Ldnull); - else - il.Emit(OpCodes.Ldstr, route); - il.Emit(OpCodes.Call, registerClosed); - } - il.Emit(OpCodes.Ret); - InjectModuleInitializer(module, initialize); - } - - private static void InjectModuleInitializer(ModuleDefinition module, MethodReference register) - { - var moduleType = module.Types.First(type => type.Name == ""); - var initializer = moduleType.Methods.FirstOrDefault(method => method.Name == ".cctor"); - if (initializer == null) - { - initializer = new MethodDefinition(".cctor", - MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | - MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, - module.TypeSystem.Void); - initializer.Body.GetILProcessor().Emit(OpCodes.Ret); - moduleType.Methods.Add(initializer); - } - var il = initializer.Body.GetILProcessor(); - il.InsertBefore(initializer.Body.Instructions[0], il.Create(OpCodes.Call, register)); - } - - private static bool HasAttribute(ICustomAttributeProvider provider, TypeReference attributeType) => - provider.CustomAttributes.Any(attribute => - attribute.AttributeType.FullName == attributeType.FullName); - - private static IEnumerable GetAllTypes(IEnumerable roots) - { - foreach (var type in roots) - { - yield return type; - foreach (var nested in GetAllTypes(type.NestedTypes)) - yield return nested; - } - } - - private static TypeReference? ResolveType(ModuleDefinition module, string fullName, - string assemblyName) - { - var reference = module.AssemblyReferences.FirstOrDefault(item => item.Name == assemblyName); - var definition = reference == null ? null : module.AssemblyResolver.Resolve(reference); - var type = definition?.MainModule.GetType(fullName); - return type == null ? null : module.ImportReference(type); - } - - private static AssemblyDefinition ReadAssembly(ICompiledAssembly compiledAssembly) - { - var resolver = new PostProcessorAssemblyResolver(compiledAssembly); - var parameters = new ReaderParameters - { - SymbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData.ToArray()), - SymbolReaderProvider = new PdbReaderProvider(), - AssemblyResolver = resolver, - ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(), - ReadingMode = ReadingMode.Immediate - }; - var assembly = AssemblyDefinition.ReadAssembly( - new MemoryStream(compiledAssembly.InMemoryAssembly.PeData.ToArray()), parameters); - resolver.AddAssemblyDefinitionBeingOperatedOn(assembly); - return assembly; - } - - private static ILPostProcessResult WriteAssembly(AssemblyDefinition assembly, - List diagnostics) - { - var pe = new MemoryStream(); - var pdb = new MemoryStream(); - assembly.Write(pe, new WriterParameters - { - SymbolWriterProvider = new PdbWriterProvider(), - SymbolStream = pdb, - WriteSymbols = true - }); - return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), diagnostics); - } + public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) => + WillProcess(compiledAssembly) + ? UnityShrinkCodeGenAdapter.Process(compiledAssembly, "ShrinkNetwork.EventBus.CodeGen") + : new ILPostProcessResult(compiledAssembly.InMemoryAssembly, new List()); } } diff --git a/CodeGen/Editor/Unity.ShrinkNetwork.EventBus.CodeGen.asmdef b/CodeGen/Editor/Unity.ShrinkNetwork.EventBus.CodeGen.asmdef index e5d4051..6d5900f 100644 --- a/CodeGen/Editor/Unity.ShrinkNetwork.EventBus.CodeGen.asmdef +++ b/CodeGen/Editor/Unity.ShrinkNetwork.EventBus.CodeGen.asmdef @@ -3,7 +3,8 @@ "rootNamespace": "ShrinkNetwork.Integration.CodeGen", "references": [ "ShrinkNetwork.Integration.EventBus", - "Unity.ShrinkEventBus.CodeGen" + "Unity.ShrinkEventBus.CodeGen", + "Unity.ShrinkShared.CodeGen" ], "includePlatforms": ["Editor"], "excludePlatforms": [], diff --git a/ShrinkNetwork.Integration.EventBus.asmdef b/ShrinkNetwork.Integration.EventBus.asmdef index ce4fd80..a06da4b 100644 --- a/ShrinkNetwork.Integration.EventBus.asmdef +++ b/ShrinkNetwork.Integration.EventBus.asmdef @@ -5,6 +5,7 @@ "ShrinkNetwork.Runtime", "ShrinkContext.Core.Runtime", "ShrinkEventBus.Runtime", + "ShrinkRuntime.Abstractions", "UniTask" ], "optionalUnityReferences": [], diff --git a/ShrinkNetworkEventBusBridge.cs b/ShrinkNetworkEventBusBridge.cs index 4e0d717..78eab3f 100644 --- a/ShrinkNetworkEventBusBridge.cs +++ b/ShrinkNetworkEventBusBridge.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Threading; using Cysharp.Threading.Tasks; using ShrinkEventBus; -using UnityEngine; +using ShrinkSDK.Runtime; namespace ShrinkNetwork.Integration { @@ -24,7 +24,9 @@ namespace ShrinkNetwork.Integration private static Dictionary _networkEventTypes = new(); private static bool _initialized; - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] +#if UNITY_5_3_OR_NEWER + [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)] +#endif private static void ResetStaticState() { EventBus.Posted -= HandleLocalEventPosted; @@ -215,9 +217,8 @@ namespace ShrinkNetwork.Integration } catch (Exception ex) { - Debug.LogException(ex); - Debug.LogError( - $"[ShrinkNetwork.Integration] 序列化网络事件失败: {eventArgs.GetType().FullName}"); + ShrinkRuntimeServices.Logger.Error( + $"[ShrinkNetwork.Integration] 序列化网络事件失败: {eventArgs.GetType().FullName}", ex); continue; } @@ -236,9 +237,8 @@ namespace ShrinkNetwork.Integration } catch (Exception ex) { - Debug.LogException(ex); - Debug.LogError( - $"[ShrinkNetwork.Integration] 转发网络事件失败: {eventArgs.GetType().FullName}, Session={session.SessionId}"); + ShrinkRuntimeServices.Logger.Error( + $"[ShrinkNetwork.Integration] 转发网络事件失败: {eventArgs.GetType().FullName}, Session={session.SessionId}", ex); } } } @@ -349,7 +349,7 @@ namespace ShrinkNetwork.Integration } catch (Exception ex) { - Debug.LogException(ex); + ShrinkRuntimeServices.Logger.Error("[ShrinkNetwork.Integration] 处理网络事件请求失败。", ex); return new ShrinkNetworkEventResultResponse { ErrorCode = ShrinkRpcErrorCode.HandlerException, @@ -481,6 +481,7 @@ namespace ShrinkNetwork.Integration /// handlers. Use ShrinkNetworkDispatchQueue when a hard per-frame budget is /// required instead of an unbounded PlayerLoop backlog. /// +#if UNITY_5_3_OR_NEWER public sealed class ShrinkNetworkUnityMainThreadDispatchScheduler : IShrinkNetworkDispatchScheduler { public async UniTask ScheduleAsync(Func callback) @@ -493,4 +494,5 @@ namespace ShrinkNetwork.Integration return true; } } +#endif } diff --git a/package.json b/package.json index fd3e966..5a37c98 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,15 @@ { "name": "com.cneicy.shrink-network-integration-eventbus", - "version": "0.1.3", + "version": "0.2.0", "displayName": "ShrinkNetwork - EventBus Integration", "description": "ShrinkNetwork 与 ShrinkEventBus 2.0 的生成式桥接层,让 IShrinkEvent 网络事件可广播、裁决并在远端重新进入命名 Bus。", "unity": "2022.3", "dependencies": { - "com.cneicy.shrink-network": "0.2.1", - "com.cneicy.shrink-context-core": "0.1.0", - "com.cneicy.shrink-eventbus": "2.0.1" + "com.cneicy.shrink-network": "0.3.0", + "com.cneicy.shrink-context-core": "0.2.0", + "com.cneicy.shrink-eventbus": "2.1.0", + "com.cneicy.shrink-shared-codegen": "0.1.0", + "com.cneicy.shrink-runtime-abstractions": "0.1.0" }, "keywords": [ "network",