public void OpenAnimSet() { SourceAnimSet = null; SourcePcc?.Dispose(); SourcePcc = null; LiveFile?.Dispose(); LiveFile = null; ActorTag = null; var dlg = new OpenFileDialog { Filter = App.ME3ME2SaveFileFilter, CheckFileExists = true, Multiselect = false, Title = "Select ME3 file containing the FaceFXAnimSet you want to edit" }; if (dlg.ShowDialog() == true) { try { SourcePcc = MEPackageHandler.OpenME3Package(dlg.FileName); } catch (FormatException) { MessageBox.Show("Must be an ME3 file!"); return; } if (EntrySelector.GetEntry <ExportEntry>(null, SourcePcc, "Choose FaceFxAnimSet to edit", exp => exp.ClassName == "FaceFXAnimSet") is ExportEntry animSetEntry) { SourceAnimSet = animSetEntry.GetBinaryData <FaceFXAnimSet>(); } } }
private static ExportEntry searchPackageForEntry(string packagePath, string fullPath, string className, List <IMEPackage> openedPackages) { //Debug.WriteLine("ME2/3 External Asset lookup: Checking " + packagePath); IMEPackage package = null; if (openedPackages != null) { package = openedPackages.FirstOrDefault(x => x.FilePath == packagePath); } package ??= MEPackageHandler.OpenMEPackage(packagePath); if (openedPackages != null && !openedPackages.Contains(package)) { openedPackages.Add(package); } var foundExp = package.Exports.FirstOrDefault(exp => exp.FullPath == fullPath && exp.ClassName == className); if (openedPackages == null) { package.Dispose(); } return(foundExp); //Debug.WriteLine("ME2/3 External Asset lookup: Not found, disposing " + packagePath); }
internal static ExportEntry FindExternalAsset(ImportEntry entry, List <ExportEntry> alreadyLoadedPackageEntries) { //Debug.WriteLine("Finding external asset " + entry.GetFullPath); if (entry.Game == MEGame.ME1) { var sourcePackageInternalPath = entry.FullPath.Substring(entry.FullPath.IndexOf('.') + 1); string baseName = entry.FileRef.FollowLink(entry.idxLink).Split('.')[0].ToUpper() + ".upk"; //Get package filename var preloadedPackageEntry = alreadyLoadedPackageEntries?.FirstOrDefault(x => Path.GetFileName(x.FileRef.FilePath).Equals(baseName, StringComparison.InvariantCultureIgnoreCase)); if (preloadedPackageEntry == null && MELoadedFiles.GetFilesLoadedInGame(MEGame.ME1).TryGetValue(baseName, out string packagePath)) { var package = MEPackageHandler.OpenMEPackage(packagePath); var foundExp = package.Exports.FirstOrDefault(exp => exp.FullPath == sourcePackageInternalPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } package.Dispose(); } else { Debug.WriteLine("ME1 External Asset lookup: Using existing preloaded export package"); var foundExp = preloadedPackageEntry.FileRef.Exports.FirstOrDefault(exp => exp.FullPath == sourcePackageInternalPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } } } else { // Next, split the filename by underscores string filenameWithoutExtension = Path.GetFileNameWithoutExtension(entry.FileRef.FilePath).ToLower(); string containingDirectory = Path.GetDirectoryName(entry.FileRef.FilePath); var packagesToCheck = new List <string>(); var gameFiles = MELoadedFiles.GetFilesLoadedInGame(entry.Game); if (filenameWithoutExtension.StartsWith("bioa_") || filenameWithoutExtension.StartsWith("biod_")) { string[] parts = filenameWithoutExtension.Split('_'); if (parts.Length >= 2) //BioA_Nor_WowThatsAlot310.pcc { string bioad = $"{parts[0]}_{parts[1]}.pcc"; string filename = Path.Combine(containingDirectory, bioad); //BioA_Nor.pcc if (File.Exists(filename)) { packagesToCheck.Add(filename); } else { if (gameFiles.TryGetValue(filename, out string inGamePath)) { packagesToCheck.Add(inGamePath); } } string biop = $"BioP_{parts[1]}.pcc"; filename = Path.Combine(containingDirectory, biop); //BioP_Nor.pcc if (File.Exists(filename)) { packagesToCheck.Add(filename); } else { if (gameFiles.TryGetValue(filename, out string inGamePath)) { packagesToCheck.Add(inGamePath); } } } } foreach (string packagePath in packagesToCheck) { var preloadedPackageEntry = alreadyLoadedPackageEntries?.FirstOrDefault(x => Path.GetFileName(x.FileRef.FilePath).Equals(packagePath, StringComparison.InvariantCultureIgnoreCase)); if (preloadedPackageEntry == null) { Debug.WriteLine("ME2/3 External Asset lookup: Checking " + packagePath); var package = MEPackageHandler.OpenMEPackage(packagePath); var foundExp = package.Exports.FirstOrDefault(exp => exp.FullPath == entry.FullPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } //Debug.WriteLine("ME2/3 External Asset lookup: Not found, disposing " + packagePath); package.Dispose(); } else { Debug.WriteLine("ME2/3 External Asset lookup: Using existing preloaded export package"); var foundExp = preloadedPackageEntry.FileRef.Exports.FirstOrDefault(exp => exp.FullPath == entry.FullPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } } } //Check SFXGame string sfxgamePath = Path.Combine(MEDirectories.CookedPath(entry.Game), "SFXGame.pcc"); if (File.Exists(sfxgamePath)) { //This is not in using statement as we have to keep this in memory. IMEPackage pcc = MEPackageHandler.OpenMEPackage(sfxgamePath); var foundExp = pcc.Exports.FirstOrDefault(exp => exp.FullPath == entry.FullPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } //Debug.WriteLine("ME2/3 External Asset lookup: Not SFXGame, disposing"); pcc.Dispose(); //Dump from memory } //Check EntryMenu string entryMenuPath = Path.Combine(MEDirectories.CookedPath(entry.Game), "EntryMenu.pcc"); if (File.Exists(entryMenuPath)) { //This is not in using statement as we have to keep this in memory. IMEPackage pcc = MEPackageHandler.OpenMEPackage(entryMenuPath); var foundExp = pcc.Exports.FirstOrDefault(exp => exp.FullPath == entry.FullPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } //Debug.WriteLine("ME2/3 External Asset lookup: Not EntryMenu, disposing"); pcc.Dispose(); //Dump from memory } //Check Startup string startupPath = Path.Combine(MEDirectories.CookedPath(entry.Game), "Startup.pcc"); if (File.Exists(startupPath)) { //This is not in using statement as we have to keep this in memory. IMEPackage pcc = MEPackageHandler.OpenMEPackage(startupPath); var foundExp = pcc.Exports.FirstOrDefault(exp => exp.FullPath == entry.FullPath && exp.ClassName == entry.ClassName); if (foundExp != null) { return(foundExp); } //Debug.WriteLine("ME2/3 External Asset lookup: Not Startup, disposing"); pcc.Dispose(); //Dump from memory } } Debug.WriteLine("Could not find external asset: " + entry.FullPath); return(null); }
/// <summary> /// Copy ME2 Static art and collision into an ME3 file. /// By Kinkojiro /// </summary> /// <param name="Game">Target Game</param> /// <param name="BioPSource">Source BioP</param> /// <param name="tgtOutputfolder">OutputFolder</param> /// <param name="BioArtsToCopy">List of level source file locations</param> /// <param name="ActorsToMove">Dicitionary: key Actors, value filename, entry uid</param> /// <param name="AssetsToMove">Dictionary key: AssetInstancedPath, value filename, isimport, entry uid</param> /// <param name="fromreload">is reloaded json</param> public static async Task <List <string> > ConvertLevelToGame(MEGame Game, IMEPackage BioPSource, string tgtOutputfolder, string tgttfc, Action <string> callbackAction, LevelConversionData conversionData = null, bool fromreload = false, bool createtestlevel = false) { //VARIABLES / VALIDATION var actorclassesToMove = new List <string>() { "BlockingVolume", "SpotLight", "SpotLightToggleable", "PointLight", "PointLightToggleable", "SkyLight", "HeightFog", "LenseFlareSource", "StaticMeshActor", "BioTriggerStream", "BioBlockingVolume" }; var actorclassesToSubstitute = new Dictionary <string, string>() { { "BioBlockingVolume", "Engine.BlockingVolume" } }; var archetypesToSubstitute = new Dictionary <string, string>() { { "Default__BioBlockingVolume", "Default__BlockingVolume" } }; var fails = new List <string>(); string busytext = null; if ((BioPSource.Game == MEGame.ME2 && ME2Directory.DefaultGamePath == null) || (BioPSource.Game == MEGame.ME1 && ME1Directory.DefaultGamePath == null) || (BioPSource.Game == MEGame.ME3 && ME3Directory.DefaultGamePath == null) || BioPSource.Game == MEGame.UDK) { fails.Add("Source Game Directory not found"); return(fails); } //Get filelist from BioP, Save a copy in outputdirectory, Collate Actors and asset information if (!fromreload) { busytext = "Collating level files..."; callbackAction?.Invoke(busytext); conversionData = new LevelConversionData(Game, BioPSource.Game, null, null, null, new ConcurrentDictionary <string, string>(), new ConcurrentDictionary <string, (string, int)>(), new ConcurrentDictionary <string, (string, int, List <string>)>()); var supportedExtensions = new List <string> { ".pcc", ".u", ".upk", ".sfm" }; if (Path.GetFileName(BioPSource.FilePath).ToLowerInvariant().StartsWith("biop_") && BioPSource.Exports.FirstOrDefault(x => x.ClassName == "BioWorldInfo") is ExportEntry BioWorld) { string biopname = Path.GetFileNameWithoutExtension(BioPSource.FilePath); conversionData.GameLevelName = biopname.Substring(5, biopname.Length - 5); var lsks = BioWorld.GetProperty <ArrayProperty <ObjectProperty> >("StreamingLevels").ToList(); if (lsks.IsEmpty()) { fails.Add("No files found in level."); return(fails); } foreach (var l in lsks) { var lskexp = BioPSource.GetUExport(l.Value); var filename = lskexp.GetProperty <NameProperty>("PackageName"); if ((filename?.Value.ToString().ToLowerInvariant().StartsWith("bioa") ?? false) || (filename?.Value.ToString().ToLowerInvariant().StartsWith("biod") ?? false)) { var filePath = Directory.GetFiles(ME2Directory.DefaultGamePath, $"{filename.Value.Instanced}.pcc", SearchOption.AllDirectories).FirstOrDefault(); conversionData.FilesToCopy.TryAdd(filename.Value.Instanced, filePath); } } conversionData.BioPSource = $"{biopname}_{BioPSource.Game}"; BioPSource.Save(Path.Combine(tgtOutputfolder, $"{conversionData.BioPSource}.pcc")); BioPSource.Dispose(); } else { fails.Add("Requires an BioP to work with."); return(fails); } busytext = "Collating actors and assets..."; callbackAction?.Invoke(busytext); Parallel.ForEach(conversionData.FilesToCopy, (pccref) => { using IMEPackage pcc = MEPackageHandler.OpenMEPackage(pccref.Value); var sourcelevel = pcc.Exports.FirstOrDefault(l => l.ClassName == "Level"); if (ObjectBinary.From(sourcelevel) is Level levelbin) { foreach (var act in levelbin.Actors) { if (act < 1) { continue; } var actor = pcc.GetUExport(act); if (actorclassesToMove.Contains(actor.ClassName)) { conversionData.ActorsToMove.TryAdd($"{pccref.Key}.{actor.InstancedFullPath}", (pccref.Key, act)); HashSet <int> actorrefs = pcc.GetReferencedEntries(true, true, actor); foreach (var r in actorrefs) { var objref = pcc.GetEntry(r); if (objref != null) { if (objref.InstancedFullPath.Contains("PersistentLevel")) //remove components of actors { continue; } string instancedPath = objref.InstancedFullPath; if (objref.idxLink == 0) { instancedPath = $"{pccref.Key}.{instancedPath}"; } var added = conversionData.AssetsToMove.TryAdd(instancedPath, (pccref.Key, r, new List <string>() { pccref.Key })); if (!added) { conversionData.AssetsToMove[instancedPath].Item3.FindOrAdd(pccref.Key); if (r > 0 && conversionData.AssetsToMove[instancedPath].Item2 < 0) //Replace imports with exports if possible { var currentlist = conversionData.AssetsToMove[instancedPath].Item3; conversionData.AssetsToMove[instancedPath] = (pccref.Key, r, currentlist); } }