public static void BuildStartupPackage() { var weaponAnims = MEPackageHandler.OpenMEPackage(@"C:\Users\mgame\source\repos\ME2Randomizer\ME2Randomizer\staticfiles\binary\WeaponAnims.pcc"); var existingSUF = MEPackageHandler.OpenMEPackage(@"B:\SteamLibrary\steamapps\common\Mass Effect 2\BioGame\DLC\DLC_PRE_General\CookedPC\Startup_PRE_General_int.pcc"); var startupFile = @"C:\Users\mgame\source\repos\ME2Randomizer\ME2Randomizer\staticfiles\binary\Startup_DLC_MOD_ME2Randomizer_INT.pcc"; MEPackageHandler.CreateAndSavePackage(startupFile, MERFileSystem.Game); var startupPackage = MEPackageHandler.OpenMEPackage(startupFile); var objReferencer = existingSUF.FindExport("ObjectReferencer_0"); objReferencer.WriteProperty(new ArrayProperty <ObjectProperty>("ReferencedObjects")); // prevent porting other stuff var sObjRefencer = EntryImporter.ImportExport(startupPackage, objReferencer, 0, true); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, weaponAnims.FindExport("WeaponAnimData"), startupPackage, null, true, out _); var referencedObjects = new ArrayProperty <ObjectProperty>("ReferencedObjects"); referencedObjects.AddRange(startupPackage.Exports.Where(x => x.ClassName == "AnimSet").Select(x => new ObjectProperty(x.UIndex))); sObjRefencer.WriteProperty(referencedObjects); startupPackage.Save(compress: true); Debug.WriteLine("Done"); }
public bool ApplyUpdate(IMEPackage package, ExportEntry targetExport, Mod installingMod) { Stream binaryStream; if (OwningMM.Assets[AssetName].AssetBinary != null) { binaryStream = new MemoryStream(OwningMM.Assets[AssetName].AssetBinary); } else { var sourcePath = FilesystemInterposer.PathCombine(installingMod.IsInArchive, installingMod.ModPath, Mod.MergeModFolderName, OwningMM.MergeModFilename); using var fileS = File.OpenRead(sourcePath); fileS.Seek(OwningMM.Assets[AssetName].FileOffset, SeekOrigin.Begin); binaryStream = fileS. ReadToMemoryStream(OwningMM.Assets[AssetName].FileSize); } using var sourcePackage = MEPackageHandler.OpenMEPackageFromStream(binaryStream); var sourceEntry = sourcePackage.FindExport(EntryName); if (sourceEntry == null) { throw new Exception(M3L.GetString(M3L.string_interp_mergefile_cannotFindAssetEntryInAssetPackage, AssetName, EntryName)); } var resultst = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.ReplaceSingular, sourceEntry, targetExport.FileRef, targetExport, true, new RelinkerOptionsPackage() { ErrorOccurredCallback = x => throw new Exception(M3L.GetString(M3L.string_interp_mergefile_errorMergingAssetsX, x)) }, out _);
public static void SetUpAnimStreamFile(string animSourceFilePath, int animSequenceUIndex, string saveAsName) { string animViewerAnimStreamFilePath = Path.Combine(App.ExecFolder, "ME3AnimViewer_StreamAnim.pcc"); using IMEPackage pcc = MEPackageHandler.OpenMEPackage(animViewerAnimStreamFilePath); if (animSourceFilePath != null) { try { const int InterpDataUIndex = 8; const int InterpTrackAnimControlUIndex = 10; const int KIS_DYN_AnimsetUIndex = 6; #if DEBUG Debug.WriteLine($"AnimViewer Loading: {animSourceFilePath} #{animSequenceUIndex}"); #endif using IMEPackage animSourceFile = MEPackageHandler.OpenMEPackage(animSourceFilePath); ExportEntry sourceAnimSeq = animSourceFile.GetUExport(animSequenceUIndex); IEntry parent = EntryImporter.GetOrAddCrossImportOrPackage(sourceAnimSeq.ParentFullPath, animSourceFile, pcc); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceAnimSeq, pcc, parent, true, out IEntry ent); ExportEntry importedAnimSeq = (ExportEntry)ent; NameReference seqName = importedAnimSeq.GetProperty <NameProperty>("SequenceName").Value; float seqLength = importedAnimSeq.GetProperty <FloatProperty>("SequenceLength"); IEntry bioAnimSet = pcc.GetEntry(importedAnimSeq.GetProperty <ObjectProperty>("m_pBioAnimSetData").Value); string setName = importedAnimSeq.ObjectName.Name.RemoveRight(seqName.Name.Length + 1); ExportEntry animInterpData = pcc.GetUExport(InterpDataUIndex); animInterpData.WriteProperty(new FloatProperty(seqLength, "InterpLength")); ExportEntry animTrack = pcc.GetUExport(InterpTrackAnimControlUIndex); var animSeqKeys = animTrack.GetProperty <ArrayProperty <StructProperty> >("AnimSeqs"); animSeqKeys[0].Properties.AddOrReplaceProp(new NameProperty(seqName, "AnimSeqName")); animTrack.WriteProperty(animSeqKeys); ExportEntry dynamicAnimSet = pcc.GetUExport(KIS_DYN_AnimsetUIndex); dynamicAnimSet.WriteProperty(new ObjectProperty(bioAnimSet.UIndex, "m_pBioAnimSetData")); dynamicAnimSet.WriteProperty(new NameProperty(setName, "m_nmOrigSetName")); dynamicAnimSet.WriteProperty(new ArrayProperty <ObjectProperty>("Sequences") { new ObjectProperty(importedAnimSeq.UIndex) }); } catch (Exception e) { MessageBox.Show($"Error Loading {animSourceFilePath} #{animSequenceUIndex}"); } } string tempFilePath = Path.Combine(ME3Directory.CookedPCPath, $"{saveAsName}.pcc"); pcc.Save(tempFilePath); InteropHelper.TryPadFile(tempFilePath, 10_485_760); }
public static void TestPropertiesInBinaryAssets() { var dlcModPath = @"C:\Users\mgame\source\repos\ME2Randomizer\ME2Randomizer\staticfiles\binary"; ReferenceCheckPackage rcp = new ReferenceCheckPackage(); bool checkCanceled = false; EntryChecker.CheckReferences(rcp, dlcModPath, EntryChecker.NonLocalizedStringConverter, x => Debug.WriteLine(x)); var cookedPC = ME2Directory.CookedPCPath; var sourcePackages = Directory.GetFiles(cookedPC, "SFX*.pcc", SearchOption.TopDirectoryOnly).Select(x => MEPackageHandler.OpenMEPackage(x)).ToList(); sourcePackages.AddRange(Directory.GetFiles(cookedPC, "Bio*.pcc", SearchOption.TopDirectoryOnly).Select(x => MEPackageHandler.OpenMEPackage(x))); foreach (var s in rcp.GetInfoWarnings()) { Debug.WriteLine($"INFO: {s.Message}"); } foreach (var s in rcp.GetSignificantIssues()) { Debug.WriteLine($"SIGNIFICANT: {s.Message}"); if (s.Entry is ExportEntry exp) { ExportEntry sourceToPull = null; foreach (var sp in sourcePackages) { sourceToPull = sp.FindExport(exp.InstancedFullPath); if (sourceToPull != null) { break; } } if (sourceToPull != null) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.ReplaceSingular, sourceToPull, exp.FileRef, exp, true, out _); Debug.WriteLine(" > REPLACED"); } } } foreach (var s in rcp.GetBlockingErrors()) { Debug.WriteLine($"BLOCKING: {s.Message}"); } var packagesToSave = rcp.GetSignificantIssues().Where(x => x.Entry != null && x.Entry.FileRef.IsModified).Select(x => x.Entry.FileRef).Distinct().ToList(); foreach (var p in packagesToSave) { p.Save(); } }
public static bool RandomizeIconicFemShep(RandomizationOption option) { var femF = MERFileSystem.GetPackageFile("BIOG_Female_Player_C.pcc"); if (femF != null && File.Exists(femF)) { var femP = MEPackageHandler.OpenMEPackage(femF); var femMorphFace = femP.GetUExport(682); RBioMorphFace.RandomizeExportNonHench(femMorphFace, option); var matSetup = femP.GetUExport(681); RBioMaterialOverride.RandomizeExport(matSetup, option); // Copy this data into BioP_Char so you get accurate results var biop_charF = MERFileSystem.GetPackageFile(@"BioP_Char.pcc"); var biop_char = MEPackageHandler.OpenMEPackage(biop_charF); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.ReplaceSingular, femMorphFace, biop_char, biop_char.GetUExport(3482), true, out IEntry _); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.ReplaceSingular, matSetup, biop_char, biop_char.GetUExport(3472), true, out IEntry _); //biop_char.GetUExport(3482).WriteProperties(femMorphFace.GetProperties()); // Copy the morph face //biop_char.GetUExport(3472).WriteProperties(matSetup.GetProperties()); // Copy the material setups MERFileSystem.SavePackage(biop_char); MERFileSystem.SavePackage(femP); } return(true); }
public static IEntry EnsureClassIsInFile(IMEPackage pcc, string className) { //check to see class is already in file foreach (ImportEntry import in pcc.Imports) { if (import.IsClass && import.ObjectName == className) { return(import); } } foreach (ExportEntry export in pcc.Exports) { if (export.IsClass && export.ObjectName == className) { return(export); } } ClassInfo info = UnrealObjectInfo.GetClassOrStructInfo(pcc.Game, className); //backup some package state so we can undo changes if something goes wrong int exportCount = pcc.ExportCount; int importCount = pcc.ImportCount; List <string> nameListBackup = pcc.Names.ToList(); try { if (EntryImporter.IsSafeToImportFrom(info.pccPath, pcc.Game)) { string package = Path.GetFileNameWithoutExtension(info.pccPath); return(pcc.getEntryOrAddImport($"{package}.{className}")); } //It's a class that's defined locally in every file that uses it. Stream loadStream = null; if (info.pccPath == UnrealObjectInfo.Me3ExplorerCustomNativeAdditionsName) { loadStream = Utilities.GetCustomAppResourceStream(pcc.Game); //string resourceFilePath = App.CustomResourceFilePath(pcc.Game); //if (File.Exists(resourceFilePath)) //{ // sourceFilePath = resourceFilePath; //} } else { string testPath = Path.Combine(MEDirectories.GetBioGamePath(pcc.Game), info.pccPath); if (File.Exists(testPath)) { loadStream = new MemoryStream(File.ReadAllBytes(testPath)); } else if (pcc.Game == MEGame.ME1) { testPath = Path.Combine(ME1Directory.DefaultGamePath, info.pccPath); if (File.Exists(testPath)) { loadStream = new MemoryStream(File.ReadAllBytes(testPath)); } } } if (loadStream == null) { //can't find file to import from. This may occur if user does not have game or neccesary dlc installed return(null); } using IMEPackage sourcePackage = MEPackageHandler.OpenMEPackageFromStream(loadStream); if (!sourcePackage.IsUExport(info.exportIndex)) { return(null); //not sure how this would happen } ExportEntry sourceClassExport = sourcePackage.GetUExport(info.exportIndex); if (sourceClassExport.ObjectName != className) { return(null); } //Will make sure that, if the class is in a package, that package will exist in pcc IEntry parent = EntryImporter.GetOrAddCrossImportOrPackage(sourceClassExport.ParentFullPath, sourcePackage, pcc); var relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceClassExport, pcc, parent, true, out IEntry result); if (relinkResults?.Count > 0) { ListDialog ld = new ListDialog(relinkResults, "Relink report", "The following items failed to relink.", null); ld.Show(); } return(result); } catch (Exception e) { //remove added entries var entriesToRemove = new List <IEntry>(); for (int i = exportCount; i < pcc.Exports.Count; i++) { entriesToRemove.Add(pcc.Exports[i]); } for (int i = importCount; i < pcc.Imports.Count; i++) { entriesToRemove.Add(pcc.Imports[i]); } EntryPruner.TrashEntries(pcc, entriesToRemove); pcc.restoreNames(nameListBackup); return(null); } }
public static void ConvertTo(this MEPackage package, MEGame newGame, string tfcPath = null, bool preserveMaterialInstances = false) { MEGame oldGame = package.Game; var prePropBinary = new List <byte[]>(package.ExportCount); var propCollections = new List <PropertyCollection>(package.ExportCount); var postPropBinary = new List <ObjectBinary>(package.ExportCount); if (oldGame == MEGame.ME1 && newGame != MEGame.ME1) { int idx = package.Names.IndexOf("BIOC_Base"); if (idx >= 0) { package.replaceName(idx, "SFXGame"); } } else if (newGame == MEGame.ME1) { int idx = package.Names.IndexOf("SFXGame"); if (idx >= 0) { package.replaceName(idx, "BIOC_Base"); } } //fix up Default_ package.Imports if (newGame == MEGame.ME3) { using IMEPackage core = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "Core.pcc")); using IMEPackage engine = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "Engine.pcc")); using IMEPackage sfxGame = MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "SFXGame.pcc")); foreach (ImportEntry defImp in package.Imports.Where(imp => imp.ObjectName.Name.StartsWith("Default_")).ToList()) { string packageName = defImp.FullPath.Split('.')[0]; IMEPackage pck = packageName switch { "Core" => core, "Engine" => engine, "SFXGame" => sfxGame, _ => null }; if (pck != null && pck.Exports.FirstOrDefault(exp => exp.ObjectName == defImp.ObjectName) is ExportEntry defExp) { List <IEntry> impChildren = defImp.GetChildren(); List <IEntry> expChildren = defExp.GetChildren(); foreach (IEntry expChild in expChildren) { if (impChildren.FirstOrDefault(imp => imp.ObjectName == expChild.ObjectName) is ImportEntry matchingImp) { impChildren.Remove(matchingImp); } else { package.AddImport(new ImportEntry(package) { idxLink = defImp.UIndex, ClassName = expChild.ClassName, ObjectName = expChild.ObjectName, PackageFile = defImp.PackageFile }); } } foreach (IEntry impChild in impChildren) { EntryPruner.TrashEntries(package, impChild.GetAllDescendants().Prepend(impChild)); } } } } //purge MaterialExpressions if (newGame == MEGame.ME3) { var entriesToTrash = new List <IEntry>(); foreach (ExportEntry mat in package.Exports.Where(exp => exp.ClassName == "Material").ToList()) { entriesToTrash.AddRange(mat.GetAllDescendants()); } EntryPruner.TrashEntries(package, entriesToTrash.ToHashSet()); } EntryPruner.TrashIncompatibleEntries(package, oldGame, newGame); foreach (ExportEntry export in package.Exports) { //convert stack, or just get the pre-prop binary if no stack prePropBinary.Add(ExportBinaryConverter.ConvertPrePropBinary(export, newGame)); PropertyCollection props = export.ClassName == "Class" ? null : EntryPruner.RemoveIncompatibleProperties(package, export.GetProperties(), export.ClassName, newGame); propCollections.Add(props); //convert binary data postPropBinary.Add(ExportBinaryConverter.ConvertPostPropBinary(export, newGame, props)); //writes header in whatever format is correct for newGame export.RegenerateHeader(newGame, true); } package.setGame(newGame); for (int i = 0; i < package.Exports.Count; i++) { package.Exports[i].WritePrePropsAndPropertiesAndBinary(prePropBinary[i], propCollections[i], postPropBinary[i]); } if (newGame != MEGame.ME3) //Fix Up Textures before Materials { foreach (ExportEntry texport in package.Exports.Where(exp => exp.IsTexture())) { texport.WriteProperty(new BoolProperty(true, "NeverStream")); } } else if (package.Exports.Any(exp => exp.IsTexture() && Texture2D.GetTexture2DMipInfos(exp, null) .Any(mip => mip.storageType == StorageTypes.pccLZO || mip.storageType == StorageTypes.pccZlib))) { //ME3 can't deal with compressed textures in a pcc, so we'll need to stuff them into a tfc tfcPath ??= Path.ChangeExtension(package.FilePath, "tfc"); string tfcName = Path.GetFileNameWithoutExtension(tfcPath); using var tfc = new FileStream(tfcPath, FileMode.OpenOrCreate, FileAccess.ReadWrite); Guid tfcGuid; if (tfc.Length >= 16) { tfcGuid = tfc.ReadGuid(); tfc.SeekEnd(); } else { tfcGuid = Guid.NewGuid(); tfc.WriteGuid(tfcGuid); } foreach (ExportEntry texport in package.Exports.Where(exp => exp.IsTexture())) { List <Texture2DMipInfo> mips = Texture2D.GetTexture2DMipInfos(texport, null); var offsets = new List <int>(); foreach (Texture2DMipInfo mipInfo in mips) { if (mipInfo.storageType == StorageTypes.pccLZO || mipInfo.storageType == StorageTypes.pccZlib) { offsets.Add((int)tfc.Position); byte[] mip = mipInfo.storageType == StorageTypes.pccLZO ? TextureCompression.CompressTexture(Texture2D.GetTextureData(mipInfo, texport.Game), StorageTypes.extZlib) : Texture2D.GetTextureData(mipInfo, texport.Game, decompress: false); tfc.WriteFromBuffer(mip); } } offsets.Add((int)tfc.Position); texport.WriteBinary(ExportBinaryConverter.ConvertTexture2D(texport, package.Game, offsets, StorageTypes.extZlib)); texport.WriteProperty(new NameProperty(tfcName, "TextureFileCacheName")); texport.WriteProperty(tfcGuid.ToGuidStructProp("TFCFileGuid")); } } if (oldGame == MEGame.ME3 && newGame != MEGame.ME3) { int idx = package.Names.IndexOf("location"); if (idx >= 0) { package.replaceName(idx, "Location"); } } else if (newGame == MEGame.ME3) { int idx = package.Names.IndexOf("Location"); if (idx >= 0) { package.replaceName(idx, "location"); } } if (newGame == MEGame.ME3) //Special handling where materials have been ported between games. { //change all materials to default material, but try to preserve diff and norm textures using var resourcePCC = MEPackageHandler.OpenMEPackageFromStream(ME3ExplorerCoreUtilities.GetCustomAppResourceStream(MEGame.ME3)); var defaultmaster = resourcePCC.Exports.First(exp => exp.ObjectName == "NormDiffMaterial"); var materiallist = package.Exports.Where(exp => exp.ClassName == "Material" || exp.ClassName == "MaterialInstanceConstant").ToList(); foreach (var mat in materiallist) { Debug.WriteLine($"Fixing up {mat.FullPath}"); var masterMat = defaultmaster; var hasDefaultMaster = true; UIndex[] textures = Array.Empty <UIndex>(); if (mat.ClassName == "Material") { textures = ObjectBinary.From <Material>(mat).SM3MaterialResource.UniformExpressionTextures; switch (mat.FullPath) { case "BioT_Volumetric.LAG_MM_Volumetric": case "BioT_Volumetric.LAG_MM_FalloffSphere": case "BioT_LevelMaster.Materials.Opaque_MM": case "BioT_LevelMaster.Materials.GUI_Lit_MM": case "BioT_LevelMaster.Materials.Signage.MM_GUIMaster_Emissive": case "BioT_LevelMaster.Materials.Signage.MM_GUIMaster_Emissive_Fallback": case "BioT_LevelMaster.Materials.Opaque_Standard_MM": case "BioT_LevelMaster.Tech_Inset_MM": case "BioT_LevelMaster.Tech_Border_MM": case "BioT_LevelMaster.Brushed_Metal": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == mat.FullPath); hasDefaultMaster = false; break; default: break; } } else if (mat.GetProperty <BoolProperty>("bHasStaticPermutationResource")?.Value == true) { if (mat.GetProperty <ObjectProperty>("Parent") is ObjectProperty parentProp && package.GetEntry(parentProp.Value) is IEntry parent && parent.ClassName == "Material") { switch (parent.FullPath) { case "BioT_LevelMaster.Materials.Opaque_MM": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == "Materials.Opaque_MM_INST"); hasDefaultMaster = false; break; case "BIOG_APL_MASTER_MATERIAL.Placeable_MM": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == "Materials.Placeable_MM_INST"); hasDefaultMaster = false; break; case "BioT_LevelMaster.Materials.Opaque_Standard_MM": masterMat = resourcePCC.Exports.First(exp => exp.FullPath == "Materials.Opaque_Standard_MM_INST"); hasDefaultMaster = false; break; default: textures = ObjectBinary.From <MaterialInstance>(mat).SM3StaticPermutationResource.UniformExpressionTextures; break; } if (!hasDefaultMaster && mat.GetProperty <ArrayProperty <StructProperty> >("TextureParameterValues") is ArrayProperty <StructProperty> texParams) { textures = texParams.Select(structProp => new UIndex(structProp.GetProp <ObjectProperty>("ParameterValue")?.Value ?? 0)).ToArray(); } } } else if (preserveMaterialInstances) { continue; } else if (mat.GetProperty <ArrayProperty <StructProperty> >("TextureParameterValues") is ArrayProperty <StructProperty> texParams) { textures = texParams.Select(structProp => new UIndex(structProp.GetProp <ObjectProperty>("ParameterValue")?.Value ?? 0)).ToArray(); } else if (mat.GetProperty <ObjectProperty>("Parent") is ObjectProperty parentProp && package.GetEntry(parentProp.Value) is ExportEntry parent && parent.ClassName == "Material") { textures = ObjectBinary.From <Material>(parent).SM3MaterialResource.UniformExpressionTextures; } if (hasDefaultMaster) { EntryImporter.ReplaceExportDataWithAnother(masterMat, mat); int norm = 0; int diff = 0; foreach (UIndex texture in textures) { if (package.GetEntry(texture) is IEntry tex) { if (diff == 0 && tex.ObjectName.Name.Contains("diff", StringComparison.OrdinalIgnoreCase)) { diff = texture; } else if (norm == 0 && tex.ObjectName.Name.Contains("norm", StringComparison.OrdinalIgnoreCase)) { norm = texture; } } } if (diff == 0) { diff = EntryImporter.GetOrAddCrossImportOrPackage("EngineMaterials.DefaultDiffuse", resourcePCC, package).UIndex; } var matBin = ObjectBinary.From <Material>(mat); matBin.SM3MaterialResource.UniformExpressionTextures = new UIndex[] { norm, diff }; mat.WriteBinary(matBin); mat.Class = package.Imports.First(imp => imp.ObjectName == "Material"); } else if (mat.ClassName == "Material") { var mmparent = EntryImporter.GetOrAddCrossImportOrPackage(masterMat.ParentFullPath, resourcePCC, package); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, masterMat, package, mmparent, true, out IEntry targetexp); mat.ReplaceAllReferencesToThisOne(targetexp); EntryPruner.TrashEntryAndDescendants(mat); } else if (mat.ClassName == "MaterialInstanceConstant") { try { var matprops = mat.GetProperties(); var parentlightguid = masterMat.GetProperty <StructProperty>("ParentLightingGuid"); matprops.AddOrReplaceProp(parentlightguid); var mguid = masterMat.GetProperty <StructProperty>("m_Guid"); matprops.AddOrReplaceProp(mguid); var lguid = masterMat.GetProperty <StructProperty>("LightingGuid"); matprops.AddOrReplaceProp(lguid); var masterBin = ObjectBinary.From <MaterialInstance>(masterMat); var matBin = ObjectBinary.From <MaterialInstance>(mat); var staticResTextures3 = masterBin.SM3StaticPermutationResource.UniformExpressionTextures.ToList(); var newtextures3 = new List <UIndex>(); var staticResTextures2 = masterBin.SM2StaticPermutationResource.UniformExpressionTextures.ToList(); var newtextures2 = new List <UIndex>(); IEntry norm = null; IEntry diff = null; IEntry spec = null; foreach (var texref in textures) { IEntry texEnt = package.GetEntry(texref); string texName = texEnt?.ObjectName ?? "None"; if (texName.ToLowerInvariant().Contains("norm")) { norm = texEnt; } else if (texName.ToLowerInvariant().Contains("diff")) { diff = texEnt; } else if (texName.ToLowerInvariant().Contains("spec")) { spec = texEnt; } else if (texName.ToLowerInvariant().Contains("msk")) { spec = texEnt; } } foreach (var texidx in staticResTextures2) { var masterTxt = resourcePCC.GetEntry(texidx); IEntry newTxtEnt = masterTxt; switch (masterTxt?.ObjectName.Name) { case "DefaultDiffuse": if (diff != null) { newTxtEnt = diff; } break; case "DefaultNormal": if (norm != null) { newTxtEnt = norm; } break; case "Gray": //Spec if (spec != null) { newTxtEnt = spec; } break; default: break; } var newtexidx = package.Exports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; if (newtexidx == 0) { newtexidx = package.Imports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; } if (newTxtEnt == masterTxt && newtexidx == 0) { var texparent = EntryImporter.GetOrAddCrossImportOrPackage(newTxtEnt.ParentFullPath, resourcePCC, package); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, newTxtEnt, package, texparent, true, out IEntry newtext); newtextures2.Add(newtext?.UIndex ?? 0); } else { newtextures2.Add(newtexidx); } } foreach (var texidx in staticResTextures3) { var masterTxt = resourcePCC.GetEntry(texidx); IEntry newTxtEnt = masterTxt; switch (masterTxt?.ObjectName) { case "DefaultDiffuse": if (diff != null) { newTxtEnt = diff; } break; case "DefaultNormal": if (norm != null) { newTxtEnt = norm; } break; case "Gray": //Spec if (spec != null) { newTxtEnt = spec; } break; default: break; } var newtexidx = package.Exports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; if (newtexidx == 0) { newtexidx = package.Imports.FirstOrDefault(x => x.FullPath == newTxtEnt.FullPath)?.UIndex ?? 0; } if (newTxtEnt == masterTxt && newtexidx == 0) { var texparent = EntryImporter.GetOrAddCrossImportOrPackage(newTxtEnt.ParentFullPath, resourcePCC, package); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, newTxtEnt, package, texparent, true, out IEntry newtext); newtextures3.Add(newtext?.UIndex ?? 0); } else { newtextures3.Add(newtexidx); } } masterBin.SM2StaticPermutationResource.UniformExpressionTextures = newtextures2.ToArray(); masterBin.SM3StaticPermutationResource.UniformExpressionTextures = newtextures3.ToArray(); mat.WritePropertiesAndBinary(matprops, masterBin); } catch { Debug.WriteLine("MaterialInstanceConversion error"); } } } } } }
/// <summary> /// Ports a power into a package /// </summary> /// <param name="targetPackage"></param> /// <param name="powerInfo"></param> /// <param name="additionalPowers">A list of additioanl powers that are referenced when this powerinfo is an import only power (prevent re-opening package)</param> /// <returns></returns> public static IEntry PortPowerIntoPackage(IMEPackage targetPackage, PowerInfo powerInfo, out IMEPackage sourcePackage) { if (powerInfo.IsCorrectedPackage) { var sourceData = MERUtilities.GetEmbeddedStaticFilesBinaryFile("correctedloadouts.powers." + powerInfo.PackageFileName); sourcePackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(sourceData)); } else { sourcePackage = NonSharedPackageCache.Cache.GetCachedPackage(powerInfo.PackageFileName); } if (sourcePackage != null) { var sourceExport = sourcePackage.GetUExport(powerInfo.SourceUIndex); if (!sourceExport.InheritsFrom("SFXPower") || sourceExport.IsDefaultObject) { throw new Exception("Wrong setup!"); } if (sourceExport.Parent != null && sourceExport.Parent.ClassName != "Package") { throw new Exception("Cannot port power - parent object is not Package!"); } var newParent = EntryExporter.PortParents(sourceExport, targetPackage); IEntry newEntry; if (powerInfo.ImportOnly) { //Debug.WriteLine($"ImportOnly in file {targetPackage.FilePath}"); if (powerInfo.RequiresStartupPackage) { ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(powerInfo.PackageFileName)); if (powerInfo.IsCorrectedPackage) { // File must be added to MERFS DLC var outP = Path.Combine(MERFileSystem.DLCModCookedPath, powerInfo.PackageFileName); if (!File.Exists(outP)) { sourcePackage.Save(outP, true); } } } newEntry = PackageTools.CreateImportForClass(sourceExport, targetPackage, newParent); // Port in extra imports so the calling class can reference them as necessary. foreach (var addlPow in powerInfo.AdditionalRequiredPowers) { var addlSourceExp = sourcePackage.FindExport(addlPow); PackageTools.CreateImportForClass(addlSourceExp, targetPackage, EntryExporter.PortParents(addlSourceExp, targetPackage)); } } else { #if DEBUG // DEBUG ONLY----------------------------------- //var defaults = sourceExport.GetDefaults(); //defaults.RemoveProperty("VFX"); //var vfx = defaults.GetProperty<ObjectProperty>("VFX").ResolveToEntry(sourcePackage) as ExportEntry; //vxx.RemoveProperty("PlayerCrust"); //vfx.FileRef.GetUExport(1544).RemoveProperty("oPrefab"); ////vfx = defaults.FileRef.GetUExport(6211); // Prefab ////vfx.RemoveProperty("WorldImpactVisualEffect"); //MERPackageCache cached = new MERPackageCache(); //EntryExporter.ExportExportToPackage(vfx, targetPackage, out newEntry, cached); //PackageTools.AddReferencesToWorld(targetPackage, new [] {newEntry as ExportEntry}); //return null; // END DEBUG ONLY-------------------------------- #endif List <EntryStringPair> relinkResults = null; if ((powerInfo.IsCorrectedPackage || (PackageTools.IsPersistentPackage(powerInfo.PackageFileName) && MERFileSystem.GetPackageFile(powerInfo.PackageFileName.ToLocalizedFilename()) == null))) { // Faster this way, without having to check imports Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. SHould probably just be part of the method relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage, newParent, true, out newEntry, crossPCCObjectMap); } else { // MEMORY SAFE (resolve imports to exports) MERPackageCache cache = new MERPackageCache(); relinkResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, cache); } if (relinkResults.Any()) { Debugger.Break(); } } return(newEntry); } return(null); // No package was found }
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); }
public void CreateLiveEditFile() { string filePath = LiveFaceFxEditorFilePath; File.Copy(Path.Combine(App.ExecFolder, "ME3EmptyLevel.pcc"), filePath); LiveFile = MEPackageHandler.OpenMEPackage(filePath); for (int i = 0; i < LiveFile.Names.Count; i++) { if (LiveFile.Names[i].Equals("ME3EmptyLevel")) { LiveFile.replaceName(i, Path.GetFileNameWithoutExtension(filePath)); } } var packguid = Guid.NewGuid(); var package = LiveFile.GetUExport(1); package.PackageGUID = packguid; LiveFile.PackageGuid = packguid; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, SourceAnimSet.Export.Parent, LiveFile, null, true, out _); var gender = SourceAnimSet.Export.ObjectNameString.Last() switch { 'F' => FaceFXGender.Female, 'M' => FaceFXGender.Male, _ => FaceFXGender.NonSpkr }; ActorTag = null; try { if (gender is not FaceFXGender.NonSpkr) { bool isFemale = gender is FaceFXGender.Female; var bioConv = LiveFile.Exports.First(exp => exp.Class.ObjectName == "BioConversation"); var LiveFileAnimSet = LiveFile.FindExport(SourceAnimSet.Export.InstancedFullPath); var propName = isFemale ? "m_aMaleFaceSets" : "m_aFemaleFaceSets"; int idx = bioConv.GetProperty <ArrayProperty <ObjectProperty> >(propName).FindIndex(objProp => objProp.Value == LiveFileAnimSet.UIndex); if (idx is 0) { //player ActorTag = $"Player_{(isFemale ? 'F' : 'M')}"; IEntry ent; using (IMEPackage soldierFile = MEPackageHandler.OpenME3Package(Path.Combine(ME3Directory.CookedPCPath, "SFXCharacterClass_Soldier.pcc"))) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, soldierFile.GetUExport(isFemale ? 10327 : 10330), LiveFile, LiveFile.GetUExport(3), true, out ent); } ExportEntry actor = (ExportEntry)ent; LiveFile.AddToLevelActorsIfNotThere(actor); actor.WriteProperty(new NameProperty(ActorTag, "Tag")); using (IMEPackage clothingFile = MEPackageHandler.OpenME3Package(Path.Combine(ME3Directory.CookedPCPath, $"BIOG_HM{(isFemale ? "F" : "M")}_ARM_CTH_R.pcc"))) { var clothingPackage = EntryImporter.GetOrAddCrossImportOrPackage("CTHa", clothingFile, LiveFile); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, clothingFile.GetUExport(isFemale ? 1625 : 1966), LiveFile, clothingPackage, true, out ent); } ExportEntry bodyComponent = LiveFile.GetUExport(actor.GetProperty <ObjectProperty>("BodyMesh").Value); bodyComponent.WriteProperty(new ObjectProperty(ent.UIndex, "SkeletalMesh")); } else if (idx is 1) { //owner using IMEPackage parentFile = getParentFile(); foreach (ExportEntry export in parentFile.Exports.Where(exp => exp.ClassName is "SFXSeqAct_StartConversation" or "SFXSeqAct_StartAmbientConv")) { if (export.GetProperty <ObjectProperty>("Conv") is ObjectProperty convProp && parentFile.TryGetImport(convProp.Value, out var convImport) && convImport.ObjectName == bioConv.ObjectName) { ExportEntry seqVar = parentFile.GetUExport(export.GetProperty <ArrayProperty <StructProperty> >("VariableLinks")[0].GetProp <ArrayProperty <ObjectProperty> >("LinkedVariables")[0].Value); if (seqVar.ClassName == "BioSeqVar_ObjectFindByTag") { ActorTag = seqVar.GetProperty <NameProperty>("m_sObjectTagToFind").Value; if (!ActorTag.StartsWith("hench_", StringComparison.OrdinalIgnoreCase)) { importTaggedActor(parentFile); } } else { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, parentFile.GetUExport(seqVar.GetProperty <ObjectProperty>("ObjValue").Value), LiveFile, LiveFile.GetUExport(3), true, out var ent); ExportEntry actor = (ExportEntry)ent; LiveFile.AddToLevelActorsIfNotThere(actor); ActorTag = actor.GetProperty <NameProperty>("Tag")?.Value.Name; if (ActorTag is null) { ActorTag = "ConvoOwner"; actor.WriteProperty(new NameProperty(ActorTag, "Tag")); } } break; } } } else { ActorTag = bioConv.GetProperty <ArrayProperty <NameProperty> >("m_aSpeakerList")[idx - 2].Value; if (!ActorTag.StartsWith("hench_", StringComparison.OrdinalIgnoreCase)) { using IMEPackage parentFile = getParentFile(); importTaggedActor(parentFile); } } } else { //find nonspkr linkage somehow } }
public static IEntry PortWeaponIntoPackage(IMEPackage targetPackage, GunInfo gunInfo) { IMEPackage sourcePackage; if (gunInfo.IsCorrectedPackage) { var sourceData = MERUtilities.GetEmbeddedStaticFilesBinaryFile("correctedloadouts.weapons." + gunInfo.PackageFileName); sourcePackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(sourceData)); if (gunInfo.ImportOnly) { // We need to install this file var outfname = Path.Combine(MERFileSystem.DLCModCookedPath, gunInfo.PackageFileName); if (!File.Exists(outfname)) { sourcePackage.Save(outfname, true); ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(gunInfo.PackageFileName)); } } } else { sourcePackage = NonSharedPackageCache.Cache.GetCachedPackage(gunInfo.PackageFileName); } if (sourcePackage != null) { var sourceExport = sourcePackage.GetUExport(gunInfo.SourceUIndex); if (!sourceExport.InheritsFrom("SFXWeapon") || sourceExport.IsDefaultObject) { throw new Exception("Wrong setup!"); } if (sourceExport.Parent != null && sourceExport.Parent.ClassName != "Package") { throw new Exception("Cannot port weapon - parent object is not Package!"); } // 1. Setup the link that will be used. //var newParent = EntryExporter.PortParents(sourceExport, targetPackage); var newParent = EntryExporter.PortParents(sourceExport, targetPackage, gunInfo.ImportOnly); void errorOccuredCB(string s) { Debugger.Break(); } IEntry newEntry = null; if (gunInfo.ImportOnly) { Debug.WriteLine($"Gun ImportOnly in file {targetPackage.FilePath}"); if (gunInfo.RequiresStartupPackage) { ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(gunInfo.PackageFileName)); } newEntry = PackageTools.CreateImportForClass(sourceExport, targetPackage, newParent); } else { List <EntryStringPair> relinkResults = null; if (gunInfo.IsCorrectedPackage || (PackageTools.IsPersistentPackage(gunInfo.PackageFileName) && MERFileSystem.GetPackageFile(gunInfo.PackageFileName.ToLocalizedFilename()) == null)) { // Faster this way, without having to check imports Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. SHould probably just be part of the method relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage, newParent, true, out newEntry, crossPCCObjectMap); } else { // MEMORY SAFE (resolve imports to exports) MERPackageCache cache = new MERPackageCache(); relinkResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, cache); } if (relinkResults.Any()) { Debugger.Break(); } } return(newEntry); } else { Debug.WriteLine($"Package for gun porting not found: {gunInfo.PackageFileName}"); } return(null); // No package was found }
public static void RunGame2EmailMerge(GameTarget target) { M3MergeDLC.RemoveMergeDLC(target); var loadedFiles = MELoadedFiles.GetFilesLoadedInGame(target.Game, gameRootOverride: target.TargetPath); // File to base modifications on using IMEPackage pcc = MEPackageHandler.OpenMEPackage(loadedFiles[@"BioD_Nor103_Messages.pcc"]); // Path to Message templates file - different files for ME2/LE2 string ResourcesFilePath = $@"MassEffectModManagerCore.modmanager.emailmerge.{target.Game}.103Message_Template_{target.Game}"; using IMEPackage resources = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream(ResourcesFilePath)); // Startup file to place conditionals and transitions into using IMEPackage startup = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream( $@"MassEffectModManagerCore.modmanager.mergedlc.{target.Game}.Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc")); var emailInfos = new List <ME2EmailMergeFile>(); var jsonSupercedances = M3Directories.GetFileSupercedances(target, new[] { @".json" }); if (jsonSupercedances.TryGetValue(EMAIL_MERGE_MANIFEST_FILE, out var jsonList)) { jsonList.Reverse(); foreach (var dlc in jsonList) { var jsonFile = Path.Combine(M3Directories.GetDLCPath(target), dlc, target.Game.CookedDirName(), EMAIL_MERGE_MANIFEST_FILE); emailInfos.Add(JsonConvert.DeserializeObject <ME2EmailMergeFile>(File.ReadAllText(jsonFile))); } } // Sanity checks if (!emailInfos.Any() || !emailInfos.SelectMany(e => e.Emails).Any()) { return; } if (emailInfos.Any(e => e.Game != target.Game)) { throw new Exception("ME2 email merge manifest targets incorrect game"); } // Startup File // Could replace this with full instanced path in M3 implementation ExportEntry stateEventMapExport = startup.Exports .First(e => e.ClassName == "BioStateEventMap" && e.ObjectName == "StateTransitionMap"); BioStateEventMap StateEventMap = stateEventMapExport.GetBinaryData <BioStateEventMap>(); ExportEntry ConditionalClass = startup.FindExport($@"PlotManager{M3MergeDLC.MERGE_DLC_FOLDERNAME}.BioAutoConditionals"); #region Sequence Exports // Send message - All email conditionals are checked and emails transitions are triggered ExportEntry SendMessageContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_Messages"); ExportEntry LastSendMessage = KismetHelper.GetSequenceObjects(SendMessageContainer).OfType <ExportEntry>() .FirstOrDefault(e => { var outbound = KismetHelper.GetOutboundLinksOfNode(e); return(outbound.Count == 1 && outbound[0].Count == 0); }); ExportEntry TemplateSendMessage = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate"); ExportEntry TemplateSendMessageBoolCheck = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate_BoolCheck"); // Mark Read - email ints are set to read // This is the only section that does not gracefully handle different DLC installations - DLC_CER is required atm ExportEntry MarkReadContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read"); ExportEntry LastMarkRead = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read.DLC_CER"); ExportEntry MarkReadOutLink = KismetHelper.GetOutboundLinksOfNode(LastMarkRead)[0][0].LinkedOp as ExportEntry; KismetHelper.RemoveOutputLinks(LastMarkRead); ExportEntry TemplateMarkRead = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_ReadTemplate"); ExportEntry TemplateMarkReadTransition = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read_Transition"); // Display Messages - Str refs are passed through to GUI ExportEntry DisplayMessageContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages"); ExportEntry DisplayMessageOutLink = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages.SeqCond_CompareBool_0"); ExportEntry LastDisplayMessage = SeqTools.FindOutboundConnectionsToNode(DisplayMessageOutLink, KismetHelper.GetSequenceObjects(DisplayMessageContainer).OfType <ExportEntry>())[0]; KismetHelper.RemoveOutputLinks(LastDisplayMessage); var DisplayMessageVariableLinks = LastDisplayMessage.GetProperty <ArrayProperty <StructProperty> >("VariableLinks"); ExportEntry TemplateDisplayMessage = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_MessageTemplate"); // Archive Messages - Message ints are set to 3 ExportEntry ArchiveContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message"); ExportEntry ArchiveSwitch = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.SeqAct_Switch_0"); ExportEntry ArchiveOutLink = pcc.FindExport( @"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.BioSeqAct_PMCheckConditional_1"); ExportEntry ExampleSetInt = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch)[0][0].LinkedOp as ExportEntry; ExportEntry ExamplePlotInt = SeqTools.GetVariableLinksOfNode(ExampleSetInt)[0].LinkedNodes[0] as ExportEntry; #endregion int messageID = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch).Count + 1; int currentSwCount = ArchiveSwitch.GetProperty <IntProperty>("LinkCount").Value; foreach (var emailMod in emailInfos) { string modName = "DLC_MOD_" + emailMod.ModName; foreach (var email in emailMod.Emails) { string emailName = modName + "_" + email.EmailName; // Create send transition int transitionId = WriteTransition(StateEventMap, email.StatusPlotInt); int conditionalId = WriteConditional(email.TriggerConditional); #region SendMessage ////////////// // SendMessage ////////////// // Create seq object var SMTemp = emailMod.InMemoryBool.HasValue ? TemplateSendMessageBoolCheck : TemplateSendMessage; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, SMTemp, pcc, SendMessageContainer, true, new RelinkerOptionsPackage(), out var outSendEntry); var newSend = outSendEntry as ExportEntry; // Set name, comment, add to sequence newSend.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newSend, SendMessageContainer); KismetHelper.SetComment(newSend, emailName); if (target.Game == MEGame.ME2) { newSend.WriteProperty(new StrProperty(emailName, "ObjName")); } // Set Trigger Conditional var pmCheckConditionalSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckConditional" && e is ExportEntry); if (pmCheckConditionalSM is ExportEntry conditional) { conditional.WriteProperty(new IntProperty(conditionalId, "m_nIndex")); KismetHelper.SetComment(conditional, "Time for " + email.EmailName + "?"); } // Set Send Transition var pmExecuteTransitionSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry); if (pmExecuteTransitionSM is ExportEntry transition) { transition.WriteProperty(new IntProperty(transitionId, "m_nIndex")); KismetHelper.SetComment(transition, "Send " + email.EmailName + " message."); } // Set Send Transition if (emailMod.InMemoryBool.HasValue) { var pmCheckStateSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckState" && e is ExportEntry); if (pmCheckStateSM is ExportEntry checkState) { checkState.WriteProperty(new IntProperty(emailMod.InMemoryBool.Value, "m_nIndex")); KismetHelper.SetComment(checkState, "Is " + emailMod.ModName + " installed?"); } } // Hook up output links KismetHelper.CreateOutputLink(LastSendMessage, "Out", newSend); LastSendMessage = newSend; #endregion #region MarkRead /////////// // MarkRead /////////// // Create seq object var MRTemp = email.ReadTransition.HasValue ? TemplateMarkReadTransition : TemplateMarkRead; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, MRTemp, pcc, MarkReadContainer, true, new RelinkerOptionsPackage(), out var outMarkReadEntry); var newMarkRead = outMarkReadEntry as ExportEntry; // Set name, comment, add to sequence newMarkRead.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newMarkRead, MarkReadContainer); KismetHelper.SetComment(newMarkRead, emailName); if (target.Game == MEGame.ME2) { newMarkRead.WriteProperty(new StrProperty(emailName, "ObjName")); } // Set Plot Int var storyManagerIntMR = newMarkRead.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry); if (storyManagerIntMR is ExportEntry plotIntMR) { plotIntMR.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); KismetHelper.SetComment(plotIntMR, email.EmailName); } if (email.ReadTransition.HasValue) { var pmExecuteTransitionMR = newMarkRead.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry); if (pmExecuteTransitionMR is ExportEntry transitionMR) { transitionMR.WriteProperty(new IntProperty(email.ReadTransition.Value, "m_nIndex")); KismetHelper.SetComment(transitionMR, "Trigger " + email.EmailName + " read transition"); } } // Hook up output links KismetHelper.CreateOutputLink(LastMarkRead, "Out", newMarkRead); LastMarkRead = newMarkRead; #endregion #region DisplayEmail //////////////// // Display Email //////////////// // Create seq object EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, TemplateDisplayMessage, pcc, DisplayMessageContainer, true, new RelinkerOptionsPackage(), out var outDisplayMessage); var newDisplayMessage = outDisplayMessage as ExportEntry; // Set name, comment, variable links, add to sequence newDisplayMessage.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newDisplayMessage, DisplayMessageContainer); newDisplayMessage.WriteProperty(DisplayMessageVariableLinks); KismetHelper.SetComment(newDisplayMessage, emailName); if (target.Game == MEGame.ME2) { newDisplayMessage.WriteProperty(new StrProperty(emailName, "ObjName")); } var displayChildren = newDisplayMessage.GetChildren(); // Set Plot Int var storyManagerIntDE = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry); if (storyManagerIntDE is ExportEntry plotIntDE) { plotIntDE.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); } // Set Email ID var emailIdDE = displayChildren.FirstOrDefault(e => e.ClassName == "SeqVar_Int" && e is ExportEntry); if (emailIdDE is ExportEntry EmailIDDE) { EmailIDDE.WriteProperty(new IntProperty(messageID, "IntValue")); } // Set Title StrRef var titleStrRef = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Title StrRef"); if (titleStrRef is ExportEntry Title) { Title.WriteProperty(new StringRefProperty(email.TitleStrRef, "m_srValue")); } // Set Description StrRef var descStrRef = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Desc StrRef"); if (descStrRef is ExportEntry Desc) { Desc.WriteProperty(new StringRefProperty(email.DescStrRef, "m_srValue")); } // Hook up output links KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", newDisplayMessage); LastDisplayMessage = newDisplayMessage; #endregion #region ArchiveEmail //////////////// // Archive Email //////////////// var NewSetInt = EntryCloner.CloneEntry(ExampleSetInt); KismetHelper.AddObjectToSequence(NewSetInt, ArchiveContainer); KismetHelper.CreateOutputLink(NewSetInt, "Out", ArchiveOutLink); KismetHelper.CreateNewOutputLink(ArchiveSwitch, "Link " + (messageID - 1), NewSetInt); var NewPlotInt = EntryCloner.CloneEntry(ExamplePlotInt); KismetHelper.AddObjectToSequence(NewPlotInt, ArchiveContainer); NewPlotInt.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); NewPlotInt.WriteProperty(new StrProperty(emailName, "m_sRefName")); var linkedVars = SeqTools.GetVariableLinksOfNode(NewSetInt); linkedVars[0].LinkedNodes = new List <IEntry>() { NewPlotInt }; SeqTools.WriteVariableLinksToNode(NewSetInt, linkedVars); messageID++; currentSwCount++; #endregion } } KismetHelper.CreateOutputLink(LastMarkRead, "Out", MarkReadOutLink); KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", DisplayMessageOutLink); ArchiveSwitch.WriteProperty(new IntProperty(currentSwCount, "LinkCount")); stateEventMapExport.WriteBinary(StateEventMap); // Save Messages file into DLC var cookedDir = Path.Combine(M3Directories.GetDLCPath(target), M3MergeDLC.MERGE_DLC_FOLDERNAME, target.Game.CookedDirName()); var outMessages = Path.Combine(cookedDir, @"BioD_Nor103_Messages.pcc"); pcc.Save(outMessages); // Save Startup file into DLC var startupF = Path.Combine(cookedDir, $@"Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc"); startup.Save(startupF); }
/// <summary> /// Ports an export into a package. Checks if the export already exists, and if it does, returns that instead. /// </summary> /// <param name="targetPackage">The target package to port into.</param> /// <param name="sourceExport">The source export to port over, including all dependencies and references.</param> /// <param name="targetLink">The target link UIndex. Only used if createParentPackages is false.</param> /// <param name="createParentPackages">If the export should be ported in the same way as it was cooked into the package natively, e.g. create the parent package paths. The export must directly sit under a Package or an exception will be thrown.</param> /// <param name="ensureMemoryUniqueness">If this object is an instance, such as a sequence object, and should be made memory-unique so it is properly used</param> /// <returns></returns> public static ExportEntry PortExportIntoPackage(IMEPackage targetPackage, ExportEntry sourceExport, int targetLink = 0, bool createParentPackages = true, bool ensureMemoryUniqueness = false, bool useMemorySafeImport = false, PackageCache cache = null) { #if DEBUG // in preprocessor to prevent this from running in release mode if (sourceExport.FileRef.FilePath != null && targetPackage.FilePath != null) { Debug.WriteLine($"Porting {sourceExport.InstancedFullPath} from {Path.GetFileName(sourceExport.FileRef.FilePath)} into {Path.GetFileName(targetPackage.FilePath)}"); } #endif var existing = targetPackage.FindExport(sourceExport.InstancedFullPath); if (existing != null) { return(existing); } // Create parent hierarchy IEntry newParent = null; if (createParentPackages) { List <IEntry> parents = new List <IEntry>(); var parent = sourceExport.Parent; while (parent != null) { if (parent.ClassName != "Package") { throw new Exception("Parent is not package!"); } parents.Add(parent); parent = parent.Parent; } // Create the parents parents.Reverse(); foreach (var p in parents) { var sourceFullPath = p.InstancedFullPath; var matchingParent = targetPackage.FindEntry(sourceFullPath); if (matchingParent != null) { newParent = matchingParent; continue; } newParent = ExportCreator.CreatePackageExport(targetPackage, p.ObjectName, newParent); } } else { newParent = targetPackage.GetEntry(targetLink); } IEntry newEntry; if (!useMemorySafeImport) { Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. Should probably just be part of the method var relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage, newParent, true, out newEntry, crossPCCObjectMap); if (relinkResults.Any()) { Debugger.Break(); } } else { // Memory safe, fixes upstream var relinkedResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, MERFileSystem.GetGlobalCache(), cache); if (relinkedResults.Any()) { Debugger.Break(); } } #if DEBUG //(sourceExport.FileRef as MEPackage).CompareToPackageDetailed(targetPackage); #endif // Helps ensure we don't have memory duplicates if (ensureMemoryUniqueness) { newEntry.ObjectName = targetPackage.GetNextIndexedName(newEntry.ObjectName); } return(newEntry as ExportEntry); }