private static ResolveEventHandler GenerateModAssemblyResolver(EverestModuleMetadata meta) => (sender, args) => { AssemblyName asmName = args?.Name == null ? null : new AssemblyName(args.Name); if (string.IsNullOrEmpty(asmName?.Name)) return null; if (!string.IsNullOrEmpty(meta.PathArchive)) { string asmPath = asmName.Name + ".dll"; using (ZipFile zip = new ZipFile(meta.PathArchive)) { foreach (ZipEntry entry in zip.Entries) { if (entry.FileName == asmPath) using (MemoryStream stream = entry.ExtractStream()) return Relinker.GetRelinkedAssembly(meta, stream); } } } if (!string.IsNullOrEmpty(meta.PathDirectory)) { string asmPath = Path.Combine(meta.PathDirectory, asmName.Name + ".dll"); if (File.Exists(asmPath)) using (FileStream stream = File.OpenRead(asmPath)) return Relinker.GetRelinkedAssembly(meta, stream); } return null; };
public static IMetadataTokenProvider Relink(this IMetadataTokenProvider mtp, Relinker relinker, IGenericParameterProvider context) { switch (mtp) { case TypeReference reference: return(reference.Relink(relinker, context)); case MethodReference reference: return(reference.Relink(relinker, context)); case FieldReference reference: return(reference.Relink(relinker, context)); case ParameterDefinition definition: return(definition.Relink(relinker, context)); case CallSite site: return(site.Relink(relinker, context)); default: throw new InvalidOperationException( $"MonoMod can't handle metadata token providers of the type {mtp.GetType()}"); } }
/// <summary> /// Relink the given member reference (metadata token provider). /// </summary> /// <param name="mtp">The reference to relink.</param> /// <param name="relinker">The relinker to use during the relinking process.</param> /// <param name="context">The generic context provided to relink generic references.</param> /// <returns>A relinked reference.</returns> public static IMetadataTokenProvider Relink(this IMetadataTokenProvider mtp, Relinker relinker, IGenericParameterProvider context) { if (mtp is TypeReference) { return(((TypeReference)mtp).Relink(relinker, context)); } #if !CECIL0_10 if (mtp is GenericParameterConstraint) { return(((GenericParameterConstraint)mtp).Relink(relinker, context)); } #endif if (mtp is MethodReference) { return(((MethodReference)mtp).Relink(relinker, context)); } if (mtp is FieldReference) { return(((FieldReference)mtp).Relink(relinker, context)); } if (mtp is ParameterDefinition) { return(((ParameterDefinition)mtp).Relink(relinker, context)); } if (mtp is CallSite) { return(((CallSite)mtp).Relink(relinker, context)); } throw new InvalidOperationException($"MonoMod can't handle metadata token providers of the type {mtp.GetType()}"); }
public static CustomAttribute Relink(this CustomAttribute attrib, Relinker relinker, IGenericParameterProvider context) { var newAttrib = new CustomAttribute(attrib.Constructor.Relink(relinker, context)); foreach (var attribArg in attrib.ConstructorArguments) { newAttrib.ConstructorArguments.Add(new CustomAttributeArgument(attribArg.Type.Relink(relinker, context), attribArg.Value)); } foreach (var attribArg in attrib.Fields) { newAttrib.Fields.Add(new CustomAttributeNamedArgument(attribArg.Name, new CustomAttributeArgument(attribArg.Argument.Type.Relink(relinker, context), attribArg.Argument.Value)) ); } foreach (var attribArg in attrib.Properties) { newAttrib.Properties.Add(new CustomAttributeNamedArgument(attribArg.Name, new CustomAttributeArgument(attribArg.Argument.Type.Relink(relinker, context), attribArg.Argument.Value)) ); } return(newAttrib); }
public static CustomAttribute Relink(this CustomAttribute attrib, Relinker relinker, IGenericParameterProvider context) { attrib.Constructor = attrib.Constructor.Relink(relinker, context); // Don't foreach when modifying the collection for (int i = 0; i < attrib.ConstructorArguments.Count; i++) { CustomAttributeArgument attribArg = attrib.ConstructorArguments[i]; attrib.ConstructorArguments[i] = new CustomAttributeArgument(attribArg.Type.Relink(relinker, context), attribArg.Value); } for (int i = 0; i < attrib.Fields.Count; i++) { CustomAttributeNamedArgument attribArg = attrib.Fields[i]; attrib.Fields[i] = new CustomAttributeNamedArgument(attribArg.Name, new CustomAttributeArgument(attribArg.Argument.Type.Relink(relinker, context), attribArg.Argument.Value) ); } for (int i = 0; i < attrib.Properties.Count; i++) { CustomAttributeNamedArgument attribArg = attrib.Properties[i]; attrib.Properties[i] = new CustomAttributeNamedArgument(attribArg.Name, new CustomAttributeArgument(attribArg.Argument.Type.Relink(relinker, context), attribArg.Argument.Value) ); } return(attrib); }
/// <summary> /// Load a mod .dll given its metadata at runtime. Doesn't load the mod content. /// </summary> /// <param name="meta">Metadata of the mod to load.</param> public static void LoadMod(EverestModuleMetadata meta) { if (!Flags.SupportRuntimeMods) { Logger.Log(LogLevel.Warn, "loader", "Loader disabled!"); return; } if (meta == null) { return; } // Add an AssemblyResolve handler for all bundled libraries. AppDomain.CurrentDomain.AssemblyResolve += GenerateModAssemblyResolver(meta); // Load the actual assembly. Assembly asm = null; if (!string.IsNullOrEmpty(meta.PathArchive)) { using (ZipFile zip = new ZipFile(meta.PathArchive)) { foreach (ZipEntry entry in zip.Entries) { string entryName = entry.FileName.Replace('\\', '/'); if (entryName == meta.DLL) { using (MemoryStream stream = entry.ExtractStream()) { if (meta.Prelinked) { asm = Assembly.Load(stream.GetBuffer()); } else { asm = Relinker.GetRelinkedAssembly(meta, stream); } } } } } } else { if (meta.Prelinked) { asm = Assembly.LoadFrom(meta.DLL); } else { using (FileStream stream = File.OpenRead(meta.DLL)) asm = Relinker.GetRelinkedAssembly(meta, stream); } } if (asm != null) { LoadModAssembly(meta, asm); } }
/// <summary> /// Load a mod .dll given its metadata at runtime. Doesn't load the mod content. /// </summary> /// <param name="meta">Metadata of the mod to load.</param> public static void LoadMod(EverestModuleMetadata meta) { if (Flags.IsDisabled || !Flags.SupportRuntimeMods) { Logger.Log(LogLevel.Warn, "loader", "Loader disabled!"); return; } if (meta == null) return; // Add an AssemblyResolve handler for all bundled libraries. AppDomain.CurrentDomain.AssemblyResolve += GenerateModAssemblyResolver(meta); ApplyRelinkerHackfixes(meta); // Load the actual assembly. Assembly asm = null; if (!string.IsNullOrEmpty(meta.PathArchive)) { bool returnEarly = false; using (ZipFile zip = new ZipFile(meta.PathArchive)) { foreach (ZipEntry entry in zip.Entries) { string entryName = entry.FileName.Replace('\\', '/'); if (entryName == meta.DLL) { using (MemoryStream stream = entry.ExtractStream()) asm = Relinker.GetRelinkedAssembly(meta, stream); } if (entryName == "main.lua") { new LuaModule(meta).Register(); returnEarly = true; } } } if (returnEarly) return; } else { if (!string.IsNullOrEmpty(meta.DLL) && File.Exists(meta.DLL)) { using (FileStream stream = File.OpenRead(meta.DLL)) asm = Relinker.GetRelinkedAssembly(meta, stream); } if (File.Exists(Path.Combine(meta.PathDirectory, "main.lua"))) { new LuaModule(meta).Register(); return; } } ApplyModHackfixes(meta, asm); if (asm == null) { // Register a null module for content mods. new NullModule(meta).Register(); return; } LoadModAssembly(meta, asm); }
public static IMetadataTokenProvider Relink(this FieldReference field, Relinker relinker, IGenericParameterProvider context) { var declaringType = field.DeclaringType.Relink(relinker, context); return(relinker( new FieldReference(field.Name, field.FieldType.Relink(relinker, declaringType), declaringType), context)); }
public static ParameterDefinition Relink(this ParameterDefinition param, Relinker relinker, IGenericParameterProvider context) { param = ((MethodReference)param.Method).Relink(relinker, context).Parameters[param.Index]; param.ParameterType = param.ParameterType.Relink(relinker, context); // Don't foreach when modifying the collection for (int i = 0; i < param.CustomAttributes.Count; i++) { param.CustomAttributes[i] = param.CustomAttributes[i].Relink(relinker, context); } return(param); }
internal static void ReloadModAssembly(object source, FileSystemEventArgs e, bool retrying = false) { if (!File.Exists(e.FullPath)) { return; } Logger.Log(LogLevel.Info, "loader", $"Reloading mod assembly: {e.FullPath}"); QueuedTaskHelper.Do("ReloadModAssembly:" + e.FullPath, () => { EverestModule module = _Modules.FirstOrDefault(m => m.Metadata.DLL == e.FullPath); if (module == null) { return; } AssetReloadHelper.Do($"{Dialog.Clean("ASSETRELOADHELPER_RELOADINGMODASSEMBLY")} {Path.GetFileName(e.FullPath)}", () => { Assembly asm = null; using (FileStream stream = File.OpenRead(e.FullPath)) asm = Relinker.GetRelinkedAssembly(module.Metadata, Path.GetFileNameWithoutExtension(e.FullPath), stream); if (asm == null) { if (!retrying) { // Retry. QueuedTaskHelper.Do("ReloadModAssembly:" + e.FullPath, () => { ReloadModAssembly(source, e, true); }); } return; } ((FileSystemWatcher)source).Dispose(); // be sure to save this module's save data and session before reloading it, so that they are not lost. if (SaveData.Instance != null) { Logger.Log("core", $"Saving save data slot {SaveData.Instance.FileSlot} for {module.Metadata} before reloading"); module.SaveSaveData(SaveData.Instance.FileSlot); if (SaveData.Instance.CurrentSession?.InArea ?? false) { Logger.Log("core", $"Saving session slot {SaveData.Instance.FileSlot} for {module.Metadata} before reloading"); module.SaveSession(SaveData.Instance.FileSlot); } } Unregister(module); LoadModAssembly(module.Metadata, asm); }); AssetReloadHelper.ReloadLevel(); }); }
public static GenericParameter Relink(this GenericParameter param, Relinker relinker, IGenericParameterProvider context) { GenericParameter newParam = new GenericParameter(param.Name, param.Owner) { Attributes = param.Attributes }.Update(param); foreach (TypeReference constraint in param.Constraints) { newParam.Constraints.Add(constraint.Relink(relinker, context)); } return(newParam); }
public static MethodReference Relink(this MethodReference method, Relinker relinker, IGenericParameterProvider context) { if (method.IsGenericInstance) { var methodg = (GenericInstanceMethod)method; var gim = new GenericInstanceMethod(methodg.ElementMethod.Relink(relinker, context)); foreach (var arg in methodg.GenericArguments) { // Generic arguments for the generic instance are often given by the next higher provider. gim.GenericArguments.Add(arg.Relink(relinker, context)); } return((MethodReference)relinker(gim, context)); } var relink = new MethodReference(method.Name, method.ReturnType, method.DeclaringType.Relink(relinker, context)) { CallingConvention = method.CallingConvention, ExplicitThis = method.ExplicitThis, HasThis = method.HasThis }; foreach (var param in method.GenericParameters) { var paramN = new GenericParameter(param.Name, param.Owner) { Attributes = param.Attributes // MetadataToken = param.MetadataToken }.Update(param); relink.GenericParameters.Add(paramN); foreach (var constraint in param.Constraints) { paramN.Constraints.Add(constraint.Relink(relinker, relink)); } } relink.ReturnType = relink.ReturnType?.Relink(relinker, relink); foreach (var param in method.Parameters) { param.ParameterType = param.ParameterType.Relink(relinker, method); relink.Parameters.Add(param); } return((MethodReference)relinker(relink, context)); }
/// <summary> /// Relink the given generic parameter reference. /// </summary> /// <param name="param">The reference to relink.</param> /// <param name="relinker">The relinker to use during the relinking process.</param> /// <param name="context">The generic context provided to relink generic references.</param> /// <returns>A relinked reference.</returns> public static GenericParameter Relink(this GenericParameter param, Relinker relinker, IGenericParameterProvider context) { GenericParameter newParam = new GenericParameter(param.Name, param.Owner) { Attributes = param.Attributes }.Update(param.Position, param.Type); #pragma warning disable IDE0008 // TypeReference in cecil 0.10, GenericParameterConstraint in cecil 0.11 foreach (var constraint in param.Constraints) #pragma warning restore IDE0008 { newParam.Constraints.Add(constraint.Relink(relinker, context)); } return(newParam); }
/// <summary> /// Relink the given method reference. /// </summary> /// <param name="method">The reference to relink.</param> /// <param name="relinker">The relinker to use during the relinking process.</param> /// <param name="context">The generic context provided to relink generic references.</param> /// <returns>A relinked reference.</returns> public static IMetadataTokenProvider Relink(this MethodReference method, Relinker relinker, IGenericParameterProvider context) { if (method.IsGenericInstance) { GenericInstanceMethod methodg = (GenericInstanceMethod)method; GenericInstanceMethod gim = new GenericInstanceMethod((MethodReference)methodg.ElementMethod.Relink(relinker, context)); foreach (TypeReference arg in methodg.GenericArguments) { // Generic arguments for the generic instance are often given by the next higher provider. gim.GenericArguments.Add(arg.Relink(relinker, context)); } return((MethodReference)relinker(gim, context)); } MethodReference relink = new MethodReference(method.Name, method.ReturnType, method.DeclaringType.Relink(relinker, context)); relink.CallingConvention = method.CallingConvention; relink.ExplicitThis = method.ExplicitThis; relink.HasThis = method.HasThis; foreach (GenericParameter param in method.GenericParameters) { GenericParameter paramN = new GenericParameter(param.Name, param.Owner) { Attributes = param.Attributes }.Update(param.Position, param.Type); relink.GenericParameters.Add(paramN); #pragma warning disable IDE0008 // TypeReference in cecil 0.10, GenericParameterConstraint in cecil 0.11 foreach (var constraint in param.Constraints) { #pragma warning restore IDE0008 paramN.Constraints.Add(constraint.Relink(relinker, relink)); } } relink.ReturnType = relink.ReturnType?.Relink(relinker, relink); foreach (ParameterDefinition param in method.Parameters) { param.ParameterType = param.ParameterType.Relink(relinker, method); relink.Parameters.Add(param); } return((MethodReference)relinker(relink, context)); }
private static ResolveEventHandler GenerateModAssemblyResolver(EverestModuleMetadata meta) => (sender, args) => { AssemblyName name = args?.Name == null ? null : new AssemblyName(args.Name); if (string.IsNullOrEmpty(name?.Name)) { return(null); } string path = name.Name + ".dll"; if (!string.IsNullOrEmpty(meta.DLL)) { path = Path.Combine(Path.GetDirectoryName(meta.DLL), path); } if (!string.IsNullOrEmpty(meta.PathArchive)) { string zipPath = path.Replace('\\', '/'); using (ZipFile zip = new ZipFile(meta.PathArchive)) { foreach (ZipEntry entry in zip.Entries) { if (entry.FileName == zipPath) { using (MemoryStream stream = entry.ExtractStream()) return(Relinker.GetRelinkedAssembly(meta, Path.GetFileNameWithoutExtension(zipPath), stream)); } } } } if (!string.IsNullOrEmpty(meta.PathDirectory)) { string filePath = path; if (!File.Exists(filePath)) { path = Path.Combine(meta.PathDirectory, filePath); } if (File.Exists(filePath)) { using (FileStream stream = File.OpenRead(filePath)) return(Relinker.GetRelinkedAssembly(meta, Path.GetFileNameWithoutExtension(filePath), stream)); } } return(null); };
/// <summary> /// Relink the given callsite. /// </summary> /// <param name="method">The reference to relink.</param> /// <param name="relinker">The relinker to use during the relinking process.</param> /// <param name="context">The generic context provided to relink generic references.</param> /// <returns>A relinked reference.</returns> public static CallSite Relink(this CallSite method, Relinker relinker, IGenericParameterProvider context) { CallSite relink = new CallSite(method.ReturnType); relink.CallingConvention = method.CallingConvention; relink.ExplicitThis = method.ExplicitThis; relink.HasThis = method.HasThis; relink.ReturnType = relink.ReturnType?.Relink(relinker, context); foreach (ParameterDefinition param in method.Parameters) { param.ParameterType = param.ParameterType.Relink(relinker, context); relink.Parameters.Add(param); } return((CallSite)relinker(relink, context)); }
/// <summary> /// Relink the given parameter definition. /// </summary> /// <param name="param">The reference to relink.</param> /// <param name="relinker">The relinker to use during the relinking process.</param> /// <param name="context">The generic context provided to relink generic references.</param> /// <returns>A relinked reference.</returns> public static ParameterDefinition Relink(this ParameterDefinition param, Relinker relinker, IGenericParameterProvider context) { param = (param.Method as MethodReference)?.Parameters[param.Index] ?? param; ParameterDefinition newParam = new ParameterDefinition(param.Name, param.Attributes, param.ParameterType.Relink(relinker, context)) { IsIn = param.IsIn, IsLcid = param.IsLcid, IsOptional = param.IsOptional, IsOut = param.IsOut, IsReturnValue = param.IsReturnValue, MarshalInfo = param.MarshalInfo }; if (param.HasConstant) { newParam.Constant = param.Constant; } return(newParam); }
internal static void ReloadModAssembly(object source, FileSystemEventArgs e, bool retrying = false) { if (!File.Exists(e.FullPath)) { return; } Logger.Log(LogLevel.Info, "loader", $"Reloading mod assembly: {e.FullPath}"); QueuedTaskHelper.Do("ReloadModAssembly:" + e.FullPath, () => { EverestModule module = _Modules.FirstOrDefault(m => m.Metadata.DLL == e.FullPath); if (module == null) { return; } AssetReloadHelper.Do($"Reloading mod assembly: {Path.GetFileName(e.FullPath)}", () => { Assembly asm = null; using (FileStream stream = File.OpenRead(e.FullPath)) asm = Relinker.GetRelinkedAssembly(module.Metadata, stream); if (asm == null) { if (!retrying) { // Retry. QueuedTaskHelper.Do("ReloadModAssembly:" + e.FullPath, () => { ReloadModAssembly(source, e, true); }); } return; } ((FileSystemWatcher)source).Dispose(); Unregister(module); LoadModAssembly(module.Metadata, asm); }); AssetReloadHelper.ReloadLevel(); }); }
public static void LoadZip(string archive) { if (!File.Exists(archive)) // Relative path? { archive = Path.Combine(PathMods, archive); } if (!File.Exists(archive)) // It just doesn't exist. { return; } Logger.Log("loader", $"Loading mod .zip: {archive}"); EverestModuleMetadata meta = null; Assembly asm = null; using (ZipFile zip = new ZipFile(archive)) { // In case the icon appears before the metadata in the .zip, store it temporarily. Texture2D icon = null; // First read the metadata, ... foreach (ZipEntry entry in zip.Entries) { if (entry.FileName == "metadata.yaml") { using (MemoryStream stream = entry.ExtractStream()) using (StreamReader reader = new StreamReader(stream)) meta = EverestModuleMetadata.Parse(archive, "", reader); continue; } if (entry.FileName == "icon.png") { using (Stream stream = entry.ExtractStream()) icon = Texture2D.FromStream(Celeste.Instance.GraphicsDevice, stream); continue; } } if (meta != null) { if (icon != null) { meta.Icon = icon; } // ... then check if the dependencies are loaded ... // TODO: Enqueue the mod, reload it on Register of other mods, rechecking if deps loaded. foreach (EverestModuleMetadata dep in meta.Dependencies) { if (!DependencyLoaded(dep)) { Logger.Log("loader", $"Dependency {dep} of mod {meta} not loaded!"); return; } } // ... then add an AssemblyResolve handler for all the .zip-ped libraries AppDomain.CurrentDomain.AssemblyResolve += GenerateModAssemblyResolver(meta); } // ... then handle the assembly ... foreach (ZipEntry entry in zip.Entries) { string entryName = entry.FileName.Replace('\\', '/'); if (meta != null && entryName == meta.DLL) { using (MemoryStream stream = entry.ExtractStream()) { if (meta.Prelinked) { asm = Assembly.Load(stream.GetBuffer()); } else { asm = Relinker.GetRelinkedAssembly(meta, stream); } } } } // ... then tell the Content class to crawl through the zip. // (This also registers the zip for recrawls further down the line.) Content.Crawl(null, archive, zip); } if (meta != null && asm != null) { LoadMod(meta, asm); } }
public static void LoadDir(string dir) { if (!Directory.Exists(dir)) // Relative path? { dir = Path.Combine(PathMods, dir); } if (!Directory.Exists(dir)) // It just doesn't exist. { return; } Logger.Log("loader", $"Loading mod directory: {dir}"); EverestModuleMetadata meta = null; Assembly asm = null; // First read the metadata, ... string metaPath = Path.Combine(dir, "metadata.yaml"); if (File.Exists(metaPath)) { using (StreamReader reader = new StreamReader(metaPath)) meta = EverestModuleMetadata.Parse("", dir, reader); } if (meta != null) { // ... then check if the dependencies are loaded ... foreach (EverestModuleMetadata dep in meta.Dependencies) { if (!DependencyLoaded(dep)) { Logger.Log("loader", $"Dependency {dep} of mod {meta} not loaded!"); return; } } // ... then add an AssemblyResolve handler for all the .zip-ped libraries AppDomain.CurrentDomain.AssemblyResolve += GenerateModAssemblyResolver(meta); } // ... then handle the assembly and all assets. Content.Crawl(null, dir); if (meta == null || !File.Exists(meta.DLL)) { return; } if (meta.Prelinked) { asm = Assembly.LoadFrom(meta.DLL); } else { using (FileStream stream = File.OpenRead(meta.DLL)) asm = Relinker.GetRelinkedAssembly(meta, stream); } if (asm != null) { LoadMod(meta, asm); } }
public static MethodBody Clone(this MethodBody bo, MethodDefinition m, Relinker relinker = null) { if (bo == null) { return(null); } var bc = new MethodBody(m) { MaxStackSize = bo.MaxStackSize, InitLocals = bo.InitLocals, LocalVarToken = bo.LocalVarToken }; bc.Instructions.AddRange(bo.Instructions.Select(o => { var c = Instruction.Create(OpCodes.Nop); c.OpCode = o.OpCode; switch (o.Operand) { case ParameterDefinition pdRef: c.Operand = m.Parameters[pdRef.Index]; break; case IMetadataTokenProvider reference when relinker != null: c.Operand = reference.Relink(relinker, m); break; default: c.Operand = o.Operand; break; } c.Offset = o.Offset; return(c); })); foreach (var c in bc.Instructions) { switch (c.Operand) { case Instruction target: c.Operand = bc.Instructions[bo.Instructions.IndexOf(target)]; break; case Instruction[] targets: c.Operand = targets.Select(i => bc.Instructions[bo.Instructions.IndexOf(i)]).ToArray(); break; } } bc.ExceptionHandlers.AddRange(bo.ExceptionHandlers.Select(o => { var c = new ExceptionHandler(o.HandlerType) { TryStart = o.TryStart == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.TryStart)], TryEnd = o.TryEnd == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.TryEnd)], FilterStart = o.FilterStart == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.FilterStart)], HandlerStart = o.HandlerStart == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.HandlerStart)], HandlerEnd = o.HandlerEnd == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.HandlerEnd)], CatchType = relinker != null ? o.CatchType.Relink(relinker, m) : o.CatchType }; return(c); })); bc.Variables.AddRange(bo.Variables.Select(o => { var c = new VariableDefinition(relinker != null ? o.VariableType.Relink(relinker, m) : o.VariableType); return(c); })); m.CustomDebugInformations.AddRange(bo.Method .CustomDebugInformations); // Abstract. TODO: Implement deep CustomDebugInformations copy. m.DebugInformation.SequencePoints.AddRange(bo.Method.DebugInformation.SequencePoints.Select(o => { var c = new SequencePoint(bc.Instructions.FirstOrDefault(i => i.Offset == o.Offset), o.Document) { StartLine = o.StartLine, StartColumn = o.StartColumn, EndLine = o.EndLine, EndColumn = o.EndColumn }; return(c); })); return(bc); }
/// <summary> /// Relink the given type reference. /// </summary> /// <param name="constraint">The reference to relink.</param> /// <param name="relinker">The relinker to use during the relinking process.</param> /// <param name="context">The generic context provided to relink generic references.</param> /// <returns>A relinked reference.</returns> public static GenericParameterConstraint Relink(this GenericParameterConstraint constraint, Relinker relinker, IGenericParameterProvider context) { if (constraint == null) { return(null); } GenericParameterConstraint relink = new GenericParameterConstraint(constraint.ConstraintType.Relink(relinker, context)); foreach (CustomAttribute attrib in constraint.CustomAttributes) { relink.CustomAttributes.Add(attrib.Relink(relinker, context)); } return(relink); }
public static string GenerateUDKFileForLevel(string udkPath, IMEPackage pcc) { #region AssetPackage string meshPackageName = $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}Meshes"; string meshFile = Path.Combine(udkPath, @"UDKGame\Content\Shared\", $"{meshPackageName}.upk"); MEPackageHandler.CreateAndSavePackage(meshFile, MEGame.UDK); using IMEPackage meshPackage = MEPackageHandler.OpenUDKPackage(meshFile); meshPackage.getEntryOrAddImport("Core.Package"); IEntry defMat = meshPackage.getEntryOrAddImport("EngineMaterials.DefaultMaterial", "Material", "Engine"); var allMats = new HashSet <int>(); var relinkMap = new Dictionary <IEntry, IEntry>(); #region StaticMeshes List <ExportEntry> staticMeshes = pcc.Exports.Where(exp => exp.ClassName == "StaticMesh").ToList(); foreach (ExportEntry mesh in staticMeshes) { var mats = new Queue <int>(); StaticMesh stm = ObjectBinary.From <StaticMesh>(mesh); foreach (StaticMeshRenderData lodModel in stm.LODModels) { foreach (StaticMeshElement meshElement in lodModel.Elements) { mats.Enqueue(meshElement.Material); allMats.Add(meshElement.Material); meshElement.Material = 0; } } if (pcc.GetEntry(stm.BodySetup) is ExportEntry rbBodySetup) { rbBodySetup.RemoveProperty("PhysMaterial"); } mesh.WriteBinary(stm); IEntry newParent = EntryImporter.GetOrAddCrossImportOrPackage(mesh.ParentFullPath, pcc, meshPackage); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, mesh, meshPackage, newParent, false, out IEntry ent, relinkMap); ExportEntry portedMesh = (ExportEntry)ent; stm = ObjectBinary.From <StaticMesh>(portedMesh); foreach (StaticMeshRenderData lodModel in stm.LODModels) { foreach (StaticMeshElement meshElement in lodModel.Elements) { meshElement.Material = mats.Dequeue(); } } portedMesh.WriteBinary(stm); } #endregion #region Materials using (IMEPackage udkResources = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetCustomAppResourceStream(MEGame.UDK))) { ExportEntry normDiffMat = udkResources.Exports.First(exp => exp.ObjectName == "NormDiffMat"); foreach (int matUIndex in allMats) { if (pcc.GetEntry(matUIndex) is ExportEntry matExp) { List <IEntry> textures = new MaterialInstanceConstant(matExp).Textures; ExportEntry diff = null; ExportEntry norm = null; foreach (IEntry texEntry in textures) { if (texEntry is ExportEntry texport) { if (texport.ObjectName.Name.ToLower().Contains("diff")) { diff = texport; } else if (texport.ObjectName.Name.ToLower().Contains("norm")) { norm = texport; } } } if (diff == null) { relinkMap[matExp] = defMat; continue; } else { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, diff, meshPackage, null, false, out IEntry ent); diff = (ExportEntry)ent; diff.RemoveProperty("TextureFileCacheName"); diff.RemoveProperty("TFCFileGuid"); diff.RemoveProperty("LODGroup"); } if (norm != null) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, norm, meshPackage, null, false, out IEntry ent); norm = (ExportEntry)ent; norm.RemoveProperty("TextureFileCacheName"); norm.RemoveProperty("TFCFileGuid"); norm.RemoveProperty("LODGroup"); } EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, normDiffMat, meshPackage, null, true, out IEntry matEnt); ExportEntry newMat = (ExportEntry)matEnt; newMat.ObjectName = matExp.ObjectName; Material matBin = ObjectBinary.From <Material>(newMat); matBin.SM3MaterialResource.UniformExpressionTextures = new UIndex[] { norm?.UIndex ?? 0, diff.UIndex }; newMat.WriteBinary(matBin); relinkMap[matExp] = newMat; if (newMat.GetProperty <ArrayProperty <ObjectProperty> >("Expressions") is {} expressionsProp&& expressionsProp.Count >= 2) { ExportEntry diffExpression = meshPackage.GetUExport(expressionsProp[0].Value); ExportEntry normExpression = meshPackage.GetUExport(expressionsProp[1].Value); diffExpression.WriteProperty(new ObjectProperty(diff.UIndex, "Texture")); normExpression.WriteProperty(new ObjectProperty(norm?.UIndex ?? 0, "Texture")); } } else if (pcc.GetEntry(matUIndex) is ImportEntry matImp) { relinkMap[matImp] = defMat; } } var relinkMapping = new OrderedMultiValueDictionary <IEntry, IEntry>(relinkMap); foreach (ExportEntry stmExport in staticMeshes) { if (relinkMap.TryGetValue(stmExport, out IEntry destEnt) && destEnt is ExportEntry destExp) { Relinker.Relink(stmExport, destExp, relinkMapping); } } } #endregion meshPackage.Save(); #endregion var staticMeshActors = new List <ExportEntry>(); var lightActors = new List <ExportEntry>(); string tempPackagePath = Path.Combine(App.ExecFolder, $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}.udk"); File.Copy(Path.Combine(App.ExecFolder, "empty.udk"), tempPackagePath, true); using IMEPackage udkPackage = MEPackageHandler.OpenUDKPackage(tempPackagePath); { var topLevelMeshPackages = new List <IEntry>(); foreach (ExportEntry exportEntry in staticMeshes) { IEntry imp = udkPackage.getEntryOrAddImport($"{exportEntry.FullPath}", "StaticMesh", "Engine", exportEntry.ObjectName.Number); while (imp.Parent != null) { imp = imp.Parent; } if (!topLevelMeshPackages.Contains(imp)) { topLevelMeshPackages.Add(imp); } } ExportEntry levelExport = udkPackage.Exports.First(exp => exp.ClassName == "Level"); List <int> actorsInLevel = ObjectBinary.From <Level>(pcc.Exports.First(exp => exp.ClassName == "Level")).Actors.Select(u => u.value).ToList(); var componentToMatrixMap = new Dictionary <int, Matrix>(); foreach (int uIndex in actorsInLevel) { if (pcc.GetEntry(uIndex) is ExportEntry stcExp) { if (stcExp.ClassName == "StaticMeshCollectionActor") { StaticMeshCollectionActor stmc = ObjectBinary.From <StaticMeshCollectionActor>(stcExp); var components = stcExp.GetProperty <ArrayProperty <ObjectProperty> >("StaticMeshComponents"); for (int i = 0; i < components.Count; i++) { componentToMatrixMap[components[i].Value] = stmc.LocalToWorldTransforms[i]; } } else if (stcExp.ClassName == "StaticLightCollectionActor") { StaticLightCollectionActor stlc = ObjectBinary.From <StaticLightCollectionActor>(stcExp); var components = stcExp.GetProperty <ArrayProperty <ObjectProperty> >("LightComponents"); for (int i = 0; i < components.Count; i++) { componentToMatrixMap[components[i].Value] = stlc.LocalToWorldTransforms[i]; } } } } #region StaticMeshActors { var emptySMCBin = new StaticMeshComponent(); IEntry staticMeshActorClass = udkPackage.getEntryOrAddImport("Engine.StaticMeshActor"); udkPackage.getEntryOrAddImport("Engine.Default__StaticMeshActor", "StaticMeshActor", "Engine"); IEntry staticMeshComponentArchetype = udkPackage.getEntryOrAddImport("Engine.Default__StaticMeshActor.StaticMeshComponent0", "StaticMeshComponent", "Engine"); int smaIndex = 2; int smcIndex = 2; foreach (ExportEntry smc in pcc.Exports.Where(exp => exp.ClassName == "StaticMeshComponent")) { if (smc.Parent is ExportEntry parent && actorsInLevel.Contains(parent.UIndex) && parent.IsA("StaticMeshActorBase")) { StructProperty locationProp; StructProperty rotationProp; StructProperty scaleProp = null; smc.CondenseArchetypes(); if (!(smc.GetProperty <ObjectProperty>("StaticMesh") is { } meshProp) || !pcc.IsUExport(meshProp.Value)) { continue; } smc.WriteBinary(emptySMCBin); smc.RemoveProperty("bBioIsReceivingDecals"); smc.RemoveProperty("bBioForcePrecomputedShadows"); //smc.RemoveProperty("bUsePreComputedShadows"); smc.RemoveProperty("bAcceptsLights"); smc.RemoveProperty("IrrelevantLights"); smc.RemoveProperty("Materials"); //should make use of this? smc.ObjectName = new NameReference("StaticMeshComponent", smcIndex++); if (parent.ClassName == "StaticMeshCollectionActor") { if (!componentToMatrixMap.TryGetValue(smc.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); //smc.WriteProperty(CommonStructs.Matrix(m, "CachedParentToWorld")); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry sma = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, staticMeshActorClass.UIndex)) { ObjectName = new NameReference("StaticMeshActor", smaIndex++), Class = staticMeshActorClass, Parent = levelExport }; sma.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(sma); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, smc, udkPackage, sma, true, out IEntry result); var props = new PropertyCollection { new ObjectProperty(result.UIndex, "StaticMeshComponent"), new NameProperty(new NameReference(Path.GetFileNameWithoutExtension(smc.FileRef.FilePath), smc.UIndex), "Tag"), new ObjectProperty(result.UIndex, "CollisionComponent") }; if (locationProp != null) { props.Add(locationProp); } if (rotationProp != null) { props.Add(rotationProp); } if (scaleProp != null) { props.Add(scaleProp); } sma.WriteProperties(props); staticMeshActors.Add(sma); } } IEntry topMeshPackageImport = udkPackage.getEntryOrAddImport(meshPackageName, "Package"); foreach (IEntry mp in topLevelMeshPackages) { mp.Parent = topMeshPackageImport; } } #endregion #region LightActors { IEntry pointLightClass = udkPackage.getEntryOrAddImport("Engine.PointLight"); IEntry spotLightClass = udkPackage.getEntryOrAddImport("Engine.SpotLight"); IEntry directionalLightClass = udkPackage.getEntryOrAddImport("Engine.DirectionalLight"); int plaIndex = 1; int plcIndex = 1; int slaIndex = 1; int slcIndex = 1; int dlaIndex = 1; int dlcIndex = 1; foreach (ExportEntry lightComponent in pcc.Exports) { if (!(lightComponent.Parent is ExportEntry parent && actorsInLevel.Contains(parent.UIndex))) { continue; } StructProperty locationProp; StructProperty rotationProp; StructProperty scaleProp; switch (lightComponent.ClassName) { case "PointLightComponent": lightComponent.CondenseArchetypes(); lightComponent.ObjectName = new NameReference("PointLightComponent", plcIndex++); if (parent.ClassName == "StaticLightCollectionActor") { if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry pla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, pointLightClass.UIndex)) { ObjectName = new NameReference("PointLight", plaIndex++), Class = pointLightClass, Parent = levelExport }; pla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(pla); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, pla, true, out IEntry portedPLC); var plsProps = new PropertyCollection { new ObjectProperty(portedPLC.UIndex, "LightComponent"), new NameProperty("PointLight", "Tag"), }; if (locationProp != null) { plsProps.Add(locationProp); } if (rotationProp != null) { plsProps.Add(rotationProp); } if (scaleProp != null) { plsProps.Add(scaleProp); } pla.WriteProperties(plsProps); lightActors.Add(pla); break; case "SpotLightComponent": lightComponent.CondenseArchetypes(); lightComponent.ObjectName = new NameReference("SpotLightComponent", slcIndex++); if (parent.ClassName == "StaticLightCollectionActor") { if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry sla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, spotLightClass.UIndex)) { ObjectName = new NameReference("SpotLight", slaIndex++), Class = spotLightClass, Parent = levelExport }; sla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(sla); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, sla, true, out IEntry portedSLC); var slaProps = new PropertyCollection { new ObjectProperty(portedSLC.UIndex, "LightComponent"), new NameProperty("SpotLight", "Tag"), }; if (locationProp != null) { slaProps.Add(locationProp); } if (rotationProp != null) { slaProps.Add(rotationProp); } if (scaleProp != null) { slaProps.Add(scaleProp); } sla.WriteProperties(slaProps); lightActors.Add(sla); break; case "DirectionalLightComponent": lightComponent.CondenseArchetypes(); lightComponent.ObjectName = new NameReference("DirectionalLightComponent", dlcIndex++); if (parent.ClassName == "StaticLightCollectionActor") { if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry dla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, directionalLightClass.UIndex)) { ObjectName = new NameReference("DirectionalLight", dlaIndex++), Class = directionalLightClass, Parent = levelExport }; dla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(dla); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, dla, true, out IEntry portedDLC); var dlaProps = new PropertyCollection { new ObjectProperty(portedDLC.UIndex, "LightComponent"), new NameProperty("DirectionalLight", "Tag"), }; if (locationProp != null) { dlaProps.Add(locationProp); } if (rotationProp != null) { dlaProps.Add(rotationProp); } if (scaleProp != null) { dlaProps.Add(scaleProp); } dla.WriteProperties(dlaProps); lightActors.Add(dla); break; } } } UDKifyLights(udkPackage); #endregion Level level = ObjectBinary.From <Level>(levelExport); level.Actors = levelExport.GetChildren().Where(ent => ent.IsA("Actor")).Select(ent => new UIndex(ent.UIndex)).ToList(); levelExport.WriteBinary(level); udkPackage.Save(); } string resultFilePath = Path.Combine(udkPath, @"UDKGame\Content\Maps\", $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}.udk"); using (IMEPackage udkPackage2 = MEPackageHandler.OpenUDKPackage(Path.Combine(App.ExecFolder, "empty.udk"))) { ExportEntry levelExport = udkPackage2.Exports.First(exp => exp.ClassName == "Level"); Level levelBin = ObjectBinary.From <Level>(levelExport); foreach (ExportEntry actor in staticMeshActors) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, actor, udkPackage2, levelExport, true, out IEntry result); levelBin.Actors.Add(result.UIndex); } foreach (ExportEntry actor in lightActors) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, actor, udkPackage2, levelExport, true, out IEntry result); levelBin.Actors.Add(result.UIndex); } levelExport.WriteBinary(levelBin); udkPackage2.Save(resultFilePath); } File.Delete(tempPackagePath); return(resultFilePath); }
/// <summary> /// Check if the signatures of a given System.Reflection and Mono.Cecil member reference match. /// </summary> /// <param name="mref">The Mono.Cecil member reference.</param> /// <param name="minfo">The System.Reflection member reference.</param> /// <returns>True if both references share the same signature, false otherwise.</returns> public static bool Is(this MemberReference mref, MemberInfo minfo) { if (mref == null) { return(false); } TypeReference mrefDecl = mref.DeclaringType; if (mrefDecl?.FullName == "<Module>") { mrefDecl = null; } if (mref is GenericParameter genParamRef) { if (!(minfo is Type genParamInfo)) { return(false); } if (!genParamInfo.IsGenericParameter) { if (genParamRef.Owner is IGenericInstance genParamRefOwner) { return(genParamRefOwner.GenericArguments[genParamRef.Position].Is(genParamInfo)); } else { return(false); } } // Don't check owner as it introduces a circular check. /* * if (!(genParamRef.Owner as MemberReference).Is(genParamInfo.DeclaringMethod ?? (System.Reflection.MemberInfo) genParamInfo.DeclaringType)) * return false; */ return(genParamRef.Position == genParamInfo.GenericParameterPosition); } if (minfo.DeclaringType != null) { if (mrefDecl == null) { return(false); } Type declType = minfo.DeclaringType; if (minfo is Type) { // Note: type.DeclaringType is supposed to == type.DeclaringType.GetGenericTypeDefinition() // For whatever reason, old versions of mono (f.e. shipped with Unity 5.0.3) break this, // requiring us to call .GetGenericTypeDefinition() manually instead. if (declType.IsGenericType && !declType.IsGenericTypeDefinition) { declType = declType.GetGenericTypeDefinition(); } } if (!mrefDecl.Is(declType)) { return(false); } } else if (mrefDecl != null) { return(false); } // Note: This doesn't work for TypeSpecification, as the reflection-side type.Name changes with some modifiers (f.e. IsArray). if (!(mref is TypeSpecification) && mref.Name != minfo.Name) { return(false); } if (mref is TypeReference typeRef) { if (!(minfo is Type typeInfo)) { return(false); } if (typeInfo.IsGenericParameter) { return(false); } if (mref is GenericInstanceType genTypeRef) { if (!typeInfo.IsGenericType) { return(false); } Collection <TypeReference> gparamRefs = genTypeRef.GenericArguments; Type[] gparamInfos = typeInfo.GetGenericArguments(); if (gparamRefs.Count != gparamInfos.Length) { return(false); } for (int i = 0; i < gparamRefs.Count; i++) { if (!gparamRefs[i].Is(gparamInfos[i])) { return(false); } } return(genTypeRef.ElementType.Is(typeInfo.GetGenericTypeDefinition())); } else if (typeRef.HasGenericParameters) { if (!typeInfo.IsGenericType) { return(false); } Collection <GenericParameter> gparamRefs = typeRef.GenericParameters; Type[] gparamInfos = typeInfo.GetGenericArguments(); if (gparamRefs.Count != gparamInfos.Length) { return(false); } for (int i = 0; i < gparamRefs.Count; i++) { if (!gparamRefs[i].Is(gparamInfos[i])) { return(false); } } } else if (typeInfo.IsGenericType) { return(false); } if (mref is ArrayType arrayTypeRef) { if (!typeInfo.IsArray) { return(false); } return(arrayTypeRef.Dimensions.Count == typeInfo.GetArrayRank() && arrayTypeRef.ElementType.Is(typeInfo.GetElementType())); } if (mref is ByReferenceType byRefTypeRef) { if (!typeInfo.IsByRef) { return(false); } return(byRefTypeRef.ElementType.Is(typeInfo.GetElementType())); } if (mref is PointerType ptrTypeRef) { if (!typeInfo.IsPointer) { return(false); } return(ptrTypeRef.ElementType.Is(typeInfo.GetElementType())); } if (mref is TypeSpecification typeSpecRef) { // Note: There are TypeSpecifications which map to non-ElementType-y reflection Types. return(typeSpecRef.ElementType.Is(typeInfo.HasElementType ? typeInfo.GetElementType() : typeInfo)); } // DeclaringType was already checked before. // Avoid converting nested type separators between + (.NET) and / (cecil) if (mrefDecl != null) { return(mref.Name == typeInfo.Name); } return(mref.FullName == typeInfo.FullName.Replace("+", "/")); } else if (minfo is Type) { return(false); } if (mref is MethodReference methodRef) { if (!(minfo is MethodBase methodInfo)) { return(false); } Collection <ParameterDefinition> paramRefs = methodRef.Parameters; ParameterInfo[] paramInfos = methodInfo.GetParameters(); if (paramRefs.Count != paramInfos.Length) { return(false); } if (mref is GenericInstanceMethod genMethodRef) { if (!methodInfo.IsGenericMethod) { return(false); } Collection <TypeReference> gparamRefs = genMethodRef.GenericArguments; Type[] gparamInfos = methodInfo.GetGenericArguments(); if (gparamRefs.Count != gparamInfos.Length) { return(false); } for (int i = 0; i < gparamRefs.Count; i++) { if (!gparamRefs[i].Is(gparamInfos[i])) { return(false); } } return(genMethodRef.ElementMethod.Is((methodInfo as System.Reflection.MethodInfo)?.GetGenericMethodDefinition() ?? methodInfo)); } else if (methodRef.HasGenericParameters) { if (!methodInfo.IsGenericMethod) { return(false); } Collection <GenericParameter> gparamRefs = methodRef.GenericParameters; Type[] gparamInfos = methodInfo.GetGenericArguments(); if (gparamRefs.Count != gparamInfos.Length) { return(false); } for (int i = 0; i < gparamRefs.Count; i++) { if (!gparamRefs[i].Is(gparamInfos[i])) { return(false); } } } else if (methodInfo.IsGenericMethod) { return(false); } Relinker resolver = null; resolver = (paramMemberRef, ctx) => paramMemberRef is TypeReference paramTypeRef?ResolveParameter(paramTypeRef) : paramMemberRef; TypeReference ResolveParameter(TypeReference paramTypeRef) { if (paramTypeRef is GenericParameter paramGenParamTypeRef) { if (paramGenParamTypeRef.Owner is MethodReference && methodRef is GenericInstanceMethod paramGenMethodRef) { return(paramGenMethodRef.GenericArguments[paramGenParamTypeRef.Position]); } if (paramGenParamTypeRef.Owner is TypeReference paramGenParamTypeRefOwnerType && methodRef.DeclaringType is GenericInstanceType genTypeRefRef && paramGenParamTypeRefOwnerType.FullName == genTypeRefRef.ElementType.FullName) // This is to prevent List<Tuple<...>> checks from incorrectly checking Tuple's args in List. { return(genTypeRefRef.GenericArguments[paramGenParamTypeRef.Position]); } return(paramTypeRef); } if (paramTypeRef == methodRef.DeclaringType.GetElementType()) { return(methodRef.DeclaringType); } return(paramTypeRef); } if (!methodRef.ReturnType.Relink(resolver, null).Is(((methodInfo as System.Reflection.MethodInfo)?.ReturnType ?? typeof(void))) && !methodRef.ReturnType.Is(((methodInfo as System.Reflection.MethodInfo)?.ReturnType ?? typeof(void)))) { return(false); } for (int i = 0; i < paramRefs.Count; i++) { if (!paramRefs[i].ParameterType.Relink(resolver, null).Is(paramInfos[i].ParameterType) && !paramRefs[i].ParameterType.Is(paramInfos[i].ParameterType)) { return(false); } } return(true); } else if (minfo is MethodInfo) { return(false); } if (mref is FieldReference != minfo is FieldInfo) { return(false); } if (mref is PropertyReference != minfo is PropertyInfo) { return(false); } if (mref is EventReference != minfo is EventInfo) { return(false); } return(true); }
public static TypeReference Relink(this TypeReference type, Relinker relinker, IGenericParameterProvider context) { if (type == null) { return(null); } if (type is TypeSpecification ts) { var relinkedElem = ts.ElementType.Relink(relinker, context); if (type.IsSentinel) { return(new SentinelType(relinkedElem)); } if (type.IsByReference) { return(new ByReferenceType(relinkedElem)); } if (type.IsPointer) { return(new PointerType(relinkedElem)); } if (type.IsPinned) { return(new PinnedType(relinkedElem)); } if (type.IsArray) { var at = new ArrayType(relinkedElem, ((ArrayType)type).Rank); for (var i = 0; i < at.Rank; i++) { // It's a struct. at.Dimensions[i] = ((ArrayType)type).Dimensions[i]; } return(at); } if (type.IsRequiredModifier) { return(new RequiredModifierType( ((RequiredModifierType)type).ModifierType.Relink(relinker, context), relinkedElem)); } if (type.IsOptionalModifier) { return(new OptionalModifierType( ((OptionalModifierType)type).ModifierType.Relink(relinker, context), relinkedElem)); } if (type.IsGenericInstance) { var git = new GenericInstanceType(relinkedElem); foreach (var genArg in ((GenericInstanceType)type).GenericArguments) { git.GenericArguments.Add(genArg?.Relink(relinker, context)); } return(git); } if (!type.IsFunctionPointer) { throw new NotSupportedException( $"MonoMod can't handle TypeSpecification: {type.FullName} ({type.GetType()})"); } var fp = (FunctionPointerType)type; fp.ReturnType = fp.ReturnType.Relink(relinker, context); foreach (var t in fp.Parameters) { t.ParameterType = t.ParameterType.Relink(relinker, context); } return(fp); } if (type.IsGenericParameter) { var genParam = context.GetGenericParameter((GenericParameter)type); if (genParam == null) { throw new RelinkTargetNotFoundException( $"{RelinkTargetNotFoundException.DefaultMessage} {type.FullName} (context: {context})", type, context); } for (var i = 0; i < genParam.Constraints.Count; i++) { if (!genParam.Constraints[i].IsGenericInstance ) // That is somehow possible and causes a stack overflow. { genParam.Constraints[i] = genParam.Constraints[i].Relink(relinker, context); } } return(genParam); } return((TypeReference)relinker(type, context)); }
protected override MethodInfo _Generate(DynamicMethodDefinition dmd, object context) { MethodDefinition def = dmd.Definition; TypeDefinition typeDef = context as TypeDefinition; bool moduleIsTemporary = false; ModuleDefinition module = typeDef?.Module; HashSet <string> accessChecksIgnored = null; if (typeDef == null) { moduleIsTemporary = true; accessChecksIgnored = new HashSet <string>(); string name = dmd.GetDumpName("Cecil"); module = ModuleDefinition.CreateModule(name, new ModuleParameters() { Kind = ModuleKind.Dll, #if !CECIL0_9 ReflectionImporterProvider = MMReflectionImporter.ProviderNoDefault #endif }); module.Assembly.CustomAttributes.Add(new CustomAttribute(module.ImportReference(DynamicMethodDefinition.c_UnverifiableCodeAttribute))); if (dmd.Debug) { CustomAttribute caDebug = new CustomAttribute(module.ImportReference(DynamicMethodDefinition.c_DebuggableAttribute)); caDebug.ConstructorArguments.Add(new CustomAttributeArgument( module.ImportReference(typeof(DebuggableAttribute.DebuggingModes)), DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default )); module.Assembly.CustomAttributes.Add(caDebug); } typeDef = new TypeDefinition( "", $"DMD<{dmd.OriginalMethod?.Name?.Replace('.', '_')}>?{GetHashCode()}", Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.Abstract | Mono.Cecil.TypeAttributes.Sealed | Mono.Cecil.TypeAttributes.Class ) { BaseType = module.TypeSystem.Object }; module.Types.Add(typeDef); } try { #pragma warning disable IDE0039 // Use local function Relinker relinker = (mtp, ctx) => { return(module.ImportReference(mtp)); }; #pragma warning restore IDE0039 // Use local function MethodDefinition clone = new MethodDefinition("_" + def.Name.Replace('.', '_'), def.Attributes, module.TypeSystem.Void) { MethodReturnType = def.MethodReturnType, Attributes = Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.Static, ImplAttributes = Mono.Cecil.MethodImplAttributes.IL | Mono.Cecil.MethodImplAttributes.Managed, DeclaringType = typeDef, NoInlining = true }; foreach (ParameterDefinition param in def.Parameters) { clone.Parameters.Add(param.Clone().Relink(relinker, clone)); } clone.ReturnType = def.ReturnType.Relink(relinker, clone); typeDef.Methods.Add(clone); clone.HasThis = def.HasThis; Mono.Cecil.Cil.MethodBody body = clone.Body = def.Body.Clone(clone); foreach (VariableDefinition var in clone.Body.Variables) { var.VariableType = var.VariableType.Relink(relinker, clone); } foreach (ExceptionHandler handler in clone.Body.ExceptionHandlers) { if (handler.CatchType != null) { handler.CatchType = handler.CatchType.Relink(relinker, clone); } } for (int instri = 0; instri < body.Instructions.Count; instri++) { Instruction instr = body.Instructions[instri]; object operand = instr.Operand; // Import references. if (operand is ParameterDefinition param) { operand = clone.Parameters[param.Index]; } else if (operand is IMetadataTokenProvider mtp) { operand = mtp.Relink(relinker, clone); } if (operand is DynamicMethodReference dmref) { // TODO: Fix up DynamicMethod inline refs. } if (accessChecksIgnored != null && operand is MemberReference mref) { IMetadataScope asmRef = (mref as TypeReference)?.Scope ?? mref.DeclaringType.Scope; if (!accessChecksIgnored.Contains(asmRef.Name)) { CustomAttribute caAccess = new CustomAttribute(module.ImportReference(DynamicMethodDefinition.c_IgnoresAccessChecksToAttribute)); caAccess.ConstructorArguments.Add(new CustomAttributeArgument( module.ImportReference(typeof(DebuggableAttribute.DebuggingModes)), asmRef.Name )); module.Assembly.CustomAttributes.Add(caAccess); accessChecksIgnored.Add(asmRef.Name); } } instr.Operand = operand; } clone.HasThis = false; if (def.HasThis) { TypeReference type = def.DeclaringType; if (type.IsValueType) { type = new ByReferenceType(type); } clone.Parameters.Insert(0, new ParameterDefinition("<>_this", Mono.Cecil.ParameterAttributes.None, type.Relink(relinker, clone))); } if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP"))) { string dir = Path.GetFullPath(Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP")); string name = module.Name + ".dll"; string path = Path.Combine(dir, name); dir = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (File.Exists(path)) { File.Delete(path); } using (Stream fileStream = File.OpenWrite(path)) module.Write(fileStream); } Assembly asm = ReflectionHelper.Load(module); return(asm.GetType(typeDef.FullName.Replace("+", "\\+"), false, false) .GetMethod(clone.Name, BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)); } finally { #if !CECIL0_9 if (moduleIsTemporary) { module.Dispose(); } #endif } }
public MethodInfo GenerateViaCecil(TypeDefinition typeDef) { MethodDefinition def = Definition; bool moduleIsPrivate = false; ModuleDefinition module = typeDef?.Module; HashSet<string> accessChecksIgnored = null; if (typeDef == null) { moduleIsPrivate = true; accessChecksIgnored = new HashSet<string>(); string name = $"DMDASM_{GetHashCode()}"; module = ModuleDefinition.CreateModule(name + ".dll", new ModuleParameters() { Kind = ModuleKind.Dll, AssemblyResolver = new AssemblyCecilDefinitionResolver(_ModuleGen, new DefaultAssemblyResolver()), ReflectionImporterProvider = new ReflectionCecilImporterProvider(null) }); #if !NETSTANDARD1_X module.Assembly.CustomAttributes.Add(new CustomAttribute(module.ImportReference(c_UnverifiableCodeAttribute))); #endif if (Debug) { CustomAttribute caDebug = new CustomAttribute(module.ImportReference(c_DebuggableAttribute)); caDebug.ConstructorArguments.Add(new CustomAttributeArgument( module.ImportReference(typeof(DebuggableAttribute.DebuggingModes)), DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default )); module.Assembly.CustomAttributes.Add(caDebug); } typeDef = new TypeDefinition( "", $"DMD<{Method?.GetFindableID(simple: true)?.Replace('.', '_')}>?{GetHashCode()}", Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.Abstract | Mono.Cecil.TypeAttributes.Sealed | Mono.Cecil.TypeAttributes.Class ) { BaseType = module.TypeSystem.Object }; module.Types.Add(typeDef); } try { #pragma warning disable IDE0039 // Use local function Relinker relinker = (mtp, ctx) => { return module.ImportReference(mtp); }; #pragma warning restore IDE0039 // Use local function MethodDefinition clone = new MethodDefinition("_" + def.Name.Replace('.', '_'), def.Attributes, module.TypeSystem.Void) { MethodReturnType = def.MethodReturnType, Attributes = Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.Static, ImplAttributes = Mono.Cecil.MethodImplAttributes.IL | Mono.Cecil.MethodImplAttributes.Managed, DeclaringType = typeDef, NoInlining = true }; foreach (ParameterDefinition param in def.Parameters) clone.Parameters.Add(param.Clone().Relink(relinker, clone)); clone.ReturnType = def.ReturnType.Relink(relinker, clone); typeDef.Methods.Add(clone); clone.HasThis = def.HasThis; Mono.Cecil.Cil.MethodBody body = clone.Body = def.Body.Clone(clone); foreach (VariableDefinition var in clone.Body.Variables) var.VariableType = var.VariableType.Relink(relinker, clone); foreach (ExceptionHandler handler in clone.Body.ExceptionHandlers) if (handler.CatchType != null) handler.CatchType = handler.CatchType.Relink(relinker, clone); for (int instri = 0; instri < body.Instructions.Count; instri++) { Instruction instr = body.Instructions[instri]; object operand = instr.Operand; // Import references. if (operand is ParameterDefinition param) { operand = clone.Parameters[param.Index]; } else if (operand is IMetadataTokenProvider mtp) { operand = mtp.Relink(relinker, clone); } if (operand is DynamicMethodReference dmref) { // TODO: Fix up DynamicMethod inline refs. } if (accessChecksIgnored != null && operand is MemberReference mref) { // TODO: Only do the following for inaccessible members. IMetadataScope asmRef = (mref as TypeReference)?.Scope ?? mref.DeclaringType.Scope; if (!accessChecksIgnored.Contains(asmRef.Name)) { CustomAttribute caAccess = new CustomAttribute(module.ImportReference(c_IgnoresAccessChecksToAttribute)); caAccess.ConstructorArguments.Add(new CustomAttributeArgument( module.ImportReference(typeof(DebuggableAttribute.DebuggingModes)), asmRef.Name )); module.Assembly.CustomAttributes.Add(caAccess); accessChecksIgnored.Add(asmRef.Name); } } instr.Operand = operand; } clone.HasThis = false; if (def.HasThis) { TypeReference type = def.DeclaringType; if (type.IsValueType) type = new ByReferenceType(type); clone.Parameters.Insert(0, new ParameterDefinition("<>_this", Mono.Cecil.ParameterAttributes.None, type.Relink(relinker, clone))); } if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP"))) { string dir = Path.GetFullPath(Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP")); string name = module.Name + ".dll"; string path = Path.Combine(dir, name); dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); if (File.Exists(path)) File.Delete(path); using (Stream fileStream = File.OpenWrite(path)) module.Write(fileStream); } Assembly asm; using (MemoryStream asmStream = new MemoryStream()) { module.Write(asmStream); asmStream.Seek(0, SeekOrigin.Begin); #if NETSTANDARD1_X // System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(asmStream); asm = (Assembly) _AssemblyLoadContext_LoadFromStream.Invoke(_AssemblyLoadContext_Default, new object[] { asmStream }); #else asm = Assembly.Load(asmStream.GetBuffer()); #endif } _DynModuleCache[module.Assembly.Name.FullName] = module.Assembly; _DynModuleReflCache[asm.GetModules()[0]] = module; _DynModuleIsPrivate = false; moduleIsPrivate = false; #if !NETSTANDARD1_X AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { if (args.Name == asm.GetName().FullName || args.Name == asm.GetName().Name || args.Name == asm.FullName) return asm; return null; }; #endif return _Postbuild(asm.GetType(typeDef.FullName.Replace("+", "\\+"), false, false).GetMethod(clone.Name)); } finally { if (moduleIsPrivate) module.Dispose(); } }
public static TypeReference Relink(this TypeReference type, Relinker relinker, IGenericParameterProvider context) { if (type == null) { return(null); } if (type is TypeSpecification) { TypeSpecification ts = (TypeSpecification)type; TypeReference relinkedElem = ts.ElementType.Relink(relinker, context); if (type.IsByReference) { return(new ByReferenceType(relinkedElem)); } if (type.IsPointer) { return(new PointerType(relinkedElem)); } if (type.IsPinned) { return(new PinnedType(relinkedElem)); } if (type.IsArray) { return(new ArrayType(relinkedElem, ((ArrayType)type).Dimensions.Count)); } if (type.IsRequiredModifier) { return(new RequiredModifierType(((RequiredModifierType)type).ModifierType.Relink(relinker, context), relinkedElem)); } if (type.IsOptionalModifier) { return(new OptionalModifierType(((OptionalModifierType)type).ModifierType.Relink(relinker, context), relinkedElem)); } if (type.IsGenericInstance) { GenericInstanceType git = new GenericInstanceType(relinkedElem); foreach (TypeReference genArg in ((GenericInstanceType)type).GenericArguments) { git.GenericArguments.Add(genArg?.Relink(relinker, context)); } return(git); } if (type.IsFunctionPointer) { FunctionPointerType fp = (FunctionPointerType)type; fp.ReturnType = fp.ReturnType.Relink(relinker, context); for (int i = 0; i < fp.Parameters.Count; i++) { fp.Parameters[i].ParameterType = fp.Parameters[i].ParameterType.Relink(relinker, context); } return(fp); } throw new InvalidOperationException($"MonoMod can't handle TypeSpecification: {type.FullName} ({type.GetType()})"); } if (type.IsGenericParameter) { GenericParameter genParam = context.GetGenericParameter(((GenericParameter)type).Name); for (int i = 0; i < genParam.Constraints.Count; i++) { if (!genParam.Constraints[i].IsGenericInstance) // That is somehow possible and causes a stack overflow. { genParam.Constraints[i] = genParam.Constraints[i].Relink(relinker, context); } } return(genParam); } return((TypeReference)relinker(type, context)); }
public static FieldReference Relink(this FieldReference field, Relinker relinker, IGenericParameterProvider context) { TypeReference declaringType = field.DeclaringType.Relink(relinker, context); return((FieldReference)relinker(new FieldReference(field.Name, field.FieldType.Relink(relinker, declaringType), declaringType), context)); }