/// <summary> /// Creates an ImportEntry that references the listed ExportEntry. Ensure the item will be in memory or this will crash the game! /// </summary> /// <param name="sourceExport"></param> /// <param name="targetPackage"></param> /// <returns></returns> public static ImportEntry CreateImportForClass(ExportEntry sourceExport, IMEPackage targetPackage, IEntry parentObject = null) { if (sourceExport.ClassName != "Class") { throw new Exception("Cannot reliably create import for non-class object!"); } var existingImport = targetPackage.FindImport(sourceExport.InstancedFullPath); if (existingImport != null) { return(existingImport); } ImportEntry imp = new ImportEntry(targetPackage) { ObjectName = sourceExport.ObjectName, PackageFile = "Core", //Risky... ClassName = sourceExport.ClassName, idxLink = parentObject?.UIndex ?? 0, }; targetPackage.AddImport(imp); return(imp); }
/// <summary> /// Converts an AnimSet export to an import /// </summary> /// <param name="origEntry"></param> /// <param name="targetPackage"></param> /// <returns></returns> private static IEntry ConvertAnimSetExportToImport(IEntry origEntry, IMEPackage targetPackage) { // Check if this item is available already var found = targetPackage.FindEntry(origEntry.InstancedFullPath); if (found != null) { return(found); } // Setup the link for our import var parentPackage = targetPackage.FindEntry(origEntry.Parent.InstancedFullPath); if (parentPackage == null) { // We must add a package import parentPackage = new ImportEntry(targetPackage) { idxLink = 0, ClassName = "Package", ObjectName = origEntry.Parent.ObjectName, PackageFile = "Core" }; targetPackage.AddImport((ImportEntry)parentPackage); } // Install the import ImportEntry imp = new ImportEntry(targetPackage) { ClassName = origEntry.ClassName, idxLink = parentPackage.UIndex, ObjectName = origEntry.ObjectName, PackageFile = "Engine" }; targetPackage.AddImport(imp); return(imp); }
//if neccessary, will fill in parents as Package Imports (if the import you need has non-Package parents, don't use this method) public static IEntry getEntryOrAddImport(this IMEPackage pcc, string fullPath, string className = "Class", string packageFile = "Core", int?objIdx = null) { if (string.IsNullOrEmpty(fullPath)) { return(null); } //see if this import exists locally foreach (ImportEntry imp in pcc.Imports) { if (imp.FullPath == fullPath && (objIdx == null || objIdx == imp.ObjectName.Number)) { return(imp); } } //see if this is an export and exists locally foreach (ExportEntry exp in pcc.Exports) { if (exp.FullPath == fullPath && (objIdx == null || objIdx == exp.ObjectName.Number)) { return(exp); } } string[] pathParts = fullPath.Split('.'); IEntry parent = pcc.getEntryOrAddImport(string.Join(".", pathParts.Take(pathParts.Length - 1)), "Package"); var import = new ImportEntry(pcc) { idxLink = parent?.UIndex ?? 0, ClassName = className, ObjectName = new NameReference(pathParts.Last(), objIdx ?? 0), PackageFile = packageFile }; pcc.AddImport(import); return(import); }
public static IEntry GetEntryOrAddImport(IMEPackage Pcc, string importFullName) { //foreach (ImportEntry imp in Pcc.Imports) //{ // if (imp.GetFullPath == importFullName) // { // return imp; // } //} var fullPathMappingList = new List <(string fullpath, IEntry entry)>(); foreach (ImportEntry imp in Pcc.Imports) { fullPathMappingList.Add((imp.FullPath, imp)); } foreach (ExportEntry exp in Pcc.Exports) { fullPathMappingList.Add((exp.FullPath, exp)); } var directMapping = fullPathMappingList.Where(x => x.fullpath == importFullName).ToList(); if (directMapping.Count == 1) { return(directMapping[0].entry); //direct single match } //Find an upstream entry to attach our import to (we can't add exports) string[] importParts = importFullName.Split('.'); int upstreamCount = 1; IEntry upstreamEntryToAttachTo = null; string upstreamfullpath; while (upstreamCount < importParts.Length) { upstreamfullpath = string.Join(".", importParts, 0, importParts.Length - upstreamCount); var upstreammatchinglist = fullPathMappingList.Where(x => x.fullpath == upstreamfullpath).ToList(); if (upstreammatchinglist.Where(x => x.entry is ExportEntry).HasExactly(1) || upstreammatchinglist.Where(x => x.entry is ImportEntry).HasExactly(1)) { upstreamEntryToAttachTo = upstreammatchinglist[0].entry; break; } /*if (upstreamEntryToAttachTo != null) * { * break; * }*/ upstreamCount++; } //upstreamImport = Pcc.Imports.FirstOrDefault(x => x.GetFullPath == upstream); //Check if this is an export instead /* itemAsImport = Pcc.Exports.FirstOrDefault(x => x.GetFullPath == importFullName && x.indexValue == 0); * if (itemAsImport != null) * { * return itemAsImport; * }*/ //Import doesn't exist, so we're gonna need to add it //But first we need to figure out what needs to be added. //string[] importParts = importFullName.Split('.'); //List<int> upstreamLinks = new List<int>(); //0 = top level, 1 = next level... n = what we wanted to import /*ImportEntry upstreamImport = null; * string upstream = null; * while (upstreamCount < importParts.Count()) * { * upstreamfullpath = string.Join(".", importParts, 0, importParts.Count() - upstreamCount); * upstreamImport = Pcc.Imports.FirstOrDefault(x => x.GetFullPath == upstreamfullpath); * * if (upstreamImport != null) * { * break; * } * upstreamCount++; * }*/ if (upstreamEntryToAttachTo == null) { //There is nothing we can attach to. Debug.WriteLine("cannot find a top level item to attach to for " + importFullName); return(null); } //Have an upstream import, now we need to add downstream imports. ImportEntry mostdownstreamimport = null; while (upstreamCount > 0) { upstreamCount--; string fullobjectname = string.Join(".", importParts, 0, importParts.Length - upstreamCount); Dictionary <string, string> importdbinfo = ImportClassDB[fullobjectname]; var downstreamName = importParts[importParts.Length - upstreamCount - 1]; Debug.WriteLine(downstreamName); int downstreamLinkIdx = upstreamEntryToAttachTo.UIndex; Debug.WriteLine(upstreamEntryToAttachTo.FullPath); var downstreamPackageName = importdbinfo["packagefile"]; string downstreamClassName = importdbinfo["fullclasspath"]; int lastPeriodIndex = downstreamClassName.LastIndexOf("."); if (lastPeriodIndex > 0) { downstreamClassName = importdbinfo["fullclasspath"].Substring(lastPeriodIndex + 1); } //ImportEntry classImport = getOrAddImport(); //int downstreamClass = 0; //if (classImport != null) { // downstreamClass = classImport.UIndex; //no recursion pls //} else //{ // throw new Exception("No class was found for importing"); //} mostdownstreamimport = new ImportEntry(Pcc) { idxLink = downstreamLinkIdx, ClassName = downstreamClassName, ObjectName = downstreamName, PackageFile = downstreamPackageName }; Pcc.AddImport(mostdownstreamimport); upstreamEntryToAttachTo = mostdownstreamimport; } return(mostdownstreamimport); }
public static bool AttemptMerge(IMEPackage vanillaPackage, IMEPackage modifiedVanillaPackage, IMEPackage targetPackage) { PackageDelta vanillaToModifiedDelta = PackageDelta.CalculateDelta(vanillaPackage, modifiedVanillaPackage); PackageDelta vanillaToTargetDelta = PackageDelta.CalculateDelta(vanillaPackage, targetPackage); string loggingPrefix = File.Exists(targetPackage.FilePath) ? Path.GetFileName(targetPackage.FilePath) : targetPackage.FilePath; //Check merge conditions var nameConflicts = vanillaToModifiedDelta.NameDeltas.Keys.Intersect(vanillaToTargetDelta.NameDeltas.Keys).ToList(); var importConflicts = vanillaToModifiedDelta.ImportDeltas.Keys.Intersect(vanillaToTargetDelta.ImportDeltas.Keys).ToList(); var exportConflicts = vanillaToModifiedDelta.ExportDeltas.Keys.Intersect(vanillaToTargetDelta.ExportDeltas.Keys).ToList(); Log.Information($@"[{loggingPrefix}] Performing three way merge pre-check"); //Name deltas if (nameConflicts.Count > 0) { //need to check if the conflicts result in same value, in this case it would not be a conflict. foreach (int nameIndex in nameConflicts) { var modifiedName = modifiedVanillaPackage.Names[nameIndex]; var targetName = targetPackage.Names[nameIndex]; if (modifiedName != targetName) { //Differing names in same spots. Log.Information($@"[{loggingPrefix}] Cannot merge files: Name index {nameIndex} is different between modified and target."); return(false); } } } if (importConflicts.Count > 0) { //todo } if (exportConflicts.Count > 0) { //hmm... this will be a tough one. foreach (int exportTableIndex in exportConflicts) { //we will have to check sizes if we ever hope to have way to merge this var modifiedData = modifiedVanillaPackage.Exports[exportTableIndex].Data; var targetData = targetPackage.Exports[exportTableIndex].Data; if (!modifiedData.SequenceEqual(targetData)) { Log.Information($@"[{loggingPrefix}] Cannot merge files: Export table index {exportTableIndex} data is different between modified and target."); return(false); } //We will have to ignore size here somehow... //var modifiedHeader = modifiedVanillaPackage.Exports[exportTableIndex].Header; //var targetHeader = targetPackage.Exports[exportTableIndex].Header; } } //Merge is OK to perform //Apply vanilla to modified delta to target package foreach (var nameDelta in vanillaToModifiedDelta.NameDeltas) { if (nameDelta.Key >= targetPackage.NameCount) { //add it Log.Information($@"[{loggingPrefix}] Adding name {nameDelta.Value}"); targetPackage.FindNameOrAdd(nameDelta.Value); } else { Log.Information($@"[{loggingPrefix}] Updating name index {nameDelta.Key} to {nameDelta.Value}"); targetPackage.replaceName(nameDelta.Key, nameDelta.Value); } } foreach (var exportDelta in vanillaToModifiedDelta.ExportDeltas) { if (exportDelta.Key >= targetPackage.ExportCount) { //add it Log.Information($@"[{loggingPrefix}] Adding export {exportDelta.Value.InstancedFullPath}"); targetPackage.AddExport(exportDelta.Value); //not sure if this is possible } else { //gonna need this reviewed, not entirely sure this is OK to do Log.Information($@"[{loggingPrefix}] Updating export {exportDelta.Value.InstancedFullPath}"); targetPackage.Exports[exportDelta.Key].Data = exportDelta.Value.Data; targetPackage.Exports[exportDelta.Key].Header = exportDelta.Value.Header; } } foreach (var importDelta in vanillaToModifiedDelta.ImportDeltas) { if (importDelta.Key >= targetPackage.ImportCount) { //add it Log.Information($@"[{loggingPrefix}] Adding import {importDelta.Value.InstancedFullPath}"); targetPackage.AddImport(importDelta.Value); //not sure if this is possible } else { Log.Information($@"[{loggingPrefix}] Updating import {importDelta.Value.InstancedFullPath}"); //gonna need this reviewed, not entirely sure this is OK to do //targetPackage.Imports[importDelta.Key].Data = importDelta.Value.Data; targetPackage.Imports[importDelta.Key].Header = importDelta.Value.Header; } } Log.Information($@"[{loggingPrefix}] Finished three way merge"); return(true); }