public void LoadStaticMesh(int index) { try { stm = ObjectBinary.From <StaticMesh>(Pcc.GetUExport(index)); //var mesh = ObjectBinary.From <StaticMesh>(Pcc.getUExport(index)); // Load meshes for the LODs preview?.Dispose(); preview = new ModelPreview(view.Context.Device, stm, 0, view.Context.TextureCache); RefreshChosenMaterialsList(); CenterView(); // Update treeview treeView1.BeginUpdate(); treeView1.Nodes.Clear(); //treeView1.Nodes.Add(stm.ToTree()); //treeView1.Nodes[0].Expand(); treeView1.EndUpdate(); MaterialBox.Visible = false; MaterialApplyButton.Visible = false; MaterialIndexBox.Visible = false; MaterialIndexApplyButton.Visible = false; } catch (Exception e) { MessageBox.Show(ExceptionHandlerDialogWPF.FlattenException(e)); } }
public void LoadSkeletalMesh(int uindex) { DisableLODs(); UnCheckLODs(); try { skm = new SkeletalMesh(Pcc.GetUExport(uindex)); // Load preview model preview?.Dispose(); preview = new ModelPreview(view.Context.Device, skm, view.Context.TextureCache); RefreshChosenMaterialsList(); CenterView(); // Update treeview treeView1.BeginUpdate(); treeView1.Nodes.Clear(); treeView1.Nodes.Add(skm.ToTree()); treeView1.Nodes[0].Expand(); treeView1.EndUpdate(); lODToolStripMenuItem.Visible = true; lOD0ToolStripMenuItem.Enabled = true; lOD0ToolStripMenuItem.Checked = true; if (skm.LODModels.Count > 1) { lOD1ToolStripMenuItem.Enabled = true; } if (skm.LODModels.Count > 2) { lOD2ToolStripMenuItem.Enabled = true; } if (skm.LODModels.Count > 3) { lOD3ToolStripMenuItem.Enabled = true; } MaterialBox.Visible = false; MaterialApplyButton.Visible = false; MaterialIndexBox.Visible = false; MaterialIndexApplyButton.Visible = false; } catch (Exception e) { MessageBox.Show(ExceptionHandlerDialogWPF.FlattenException(e)); } }
private static string relinkUIndex(IMEPackage importingPCC, ExportEntry relinkingExport, ref int uIndex, string propertyName, OrderedMultiValueDictionary <IEntry, IEntry> crossPCCObjectMappingList, string prefix, bool importExportDependencies = false) { if (uIndex == 0) { return(null); //do not relink 0 } IMEPackage destinationPcc = relinkingExport.FileRef; if (importingPCC == destinationPcc && uIndex < 0) { return(null); //do not relink same-pcc imports. } int sourceObjReference = uIndex; //Debug.WriteLine($"{prefix} Relinking:{propertyName}"); if (crossPCCObjectMappingList.TryGetValue(entry => entry.UIndex == sourceObjReference, out IEntry targetEntry)) { //relink uIndex = targetEntry.UIndex; //Debug.WriteLine($"{prefix} Relink hit: {sourceObjReference}{propertyName} : {targetEntry.FullPath}"); } else if (uIndex < 0) //It's an unmapped import { //objProperty is currently pointing to importingPCC as that is where we read the properties from int n = uIndex; int origvalue = n; //Debug.WriteLine("Relink miss, attempting JIT relink on " + n + " " + rootNode.Text); if (importingPCC.IsImport(n)) { //Get the original import ImportEntry origImport = importingPCC.GetImport(n); string origImportFullName = origImport.FullPath; //Debug.WriteLine("We should import " + origImport.GetFullPath); IEntry crossImport = null; string linkFailedDueToError = null; try { crossImport = EntryImporter.GetOrAddCrossImportOrPackage(origImportFullName, importingPCC, destinationPcc); } catch (Exception e) { //Error during relink DebugOutput.StartDebugger("PCC Relinker"); DebugOutput.PrintLn("Exception occured during relink: "); DebugOutput.PrintLn(ExceptionHandlerDialogWPF.FlattenException(e)); DebugOutput.PrintLn("You may want to consider discarding this sessions' changes as relinking was not able to properly finish."); linkFailedDueToError = e.Message; } if (crossImport != null) { crossPCCObjectMappingList.Add(origImport, crossImport); //add to mapping to speed up future relinks uIndex = crossImport.UIndex; // Debug.WriteLine($"Relink hit: Dynamic CrossImport for {origvalue} {importingPCC.GetEntry(origvalue).FullPath} -> {uIndex}"); } else { string path = importingPCC.GetEntry(uIndex) != null?importingPCC.GetEntry(uIndex).FullPath : "Entry not found: " + uIndex; if (linkFailedDueToError != null) { Debug.WriteLine($"Relink failed: CrossImport porting failed for {relinkingExport.ObjectName.Instanced} {relinkingExport.UIndex}: {propertyName} ({uIndex}): {importingPCC.GetEntry(origvalue).FullPath}"); return($"Relink failed for {prefix}{propertyName} {uIndex} in export {path}({relinkingExport.UIndex}): {linkFailedDueToError}"); } if (destinationPcc.GetEntry(uIndex) != null) { Debug.WriteLine($"Relink failed: CrossImport porting failed for {relinkingExport.ObjectName.Instanced} {relinkingExport.UIndex}: {propertyName} ({uIndex}): {importingPCC.GetEntry(origvalue).FullPath}"); return($"Relink failed: CrossImport porting failed for {prefix}{propertyName} {uIndex} {destinationPcc.GetEntry(uIndex).FullPath} in export {relinkingExport.FullPath}({relinkingExport.UIndex})"); } return($"Relink failed: New export does not exist - this is probably a bug in cross import code for {prefix}{propertyName} {uIndex} in export {relinkingExport.FullPath}({relinkingExport.UIndex})"); } } } else { //It's an export //Attempt lookup ExportEntry sourceExport = importingPCC.GetUExport(uIndex); string fullPath = sourceExport.FullPath; int indexValue = sourceExport.indexValue; IEntry existingEntry = destinationPcc.Exports.FirstOrDefault(x => x.FullPath == fullPath && indexValue == x.indexValue); existingEntry ??= destinationPcc.Imports.FirstOrDefault(x => x.FullPath == fullPath); if (existingEntry != null) { //Debug.WriteLine($"Relink hit [EXPERIMENTAL]: Existing entry in file was found, linking to it: {uIndex} {sourceExport.InstancedFullPath} -> {existingEntry.InstancedFullPath}"); uIndex = existingEntry.UIndex; } else if (importExportDependencies) { if (!crossPCCObjectMappingList.TryGetValue(sourceExport.Parent, out IEntry parent)) { parent = EntryImporter.GetOrAddCrossImportOrPackage(sourceExport.ParentFullPath, importingPCC, destinationPcc, true, crossPCCObjectMappingList); } ExportEntry importedExport = EntryImporter.ImportExport(destinationPcc, sourceExport, parent?.UIndex ?? 0, true, crossPCCObjectMappingList); uIndex = importedExport.UIndex; } else { string path = importingPCC.GetEntry(uIndex)?.FullPath ?? $"Entry not found: {uIndex}"; Debug.WriteLine($"Relink failed in {relinkingExport.ObjectName.Instanced} {relinkingExport.UIndex}: {propertyName} {uIndex} {path}"); return($"Relink failed: {prefix}{propertyName} {uIndex} in export {relinkingExport.FullPath}({relinkingExport.UIndex})"); } } return(null); }
private void GenerateME1FileList() { // AUTO DLC MOUNTING // 1. GET LIST OF DLC DIRECTORIES, SET MAIN VARIABLES //IList() me1DLCs; // set list of directorys string DLCDirectory = ME1Directory.DLCPath; string[] dlcList = Directory.GetDirectories(DLCDirectory, "*.*", SearchOption.TopDirectoryOnly); var dlcTable = new Dictionary <int, string>(); // 2. READ AUTOLOAD.INI FROM EACH DLC. BUILD TABLE OF DIRECTORIES & MOUNTS foreach (string dlcDir in dlcList) { if (dlcDir.EndsWith("DLC_UNC", StringComparison.InvariantCultureIgnoreCase)) { dlcTable.Add(1, "DLC_UNC"); } else if (dlcDir.EndsWith("DLC_VEGAS", StringComparison.InvariantCultureIgnoreCase)) { dlcTable.Add(2, "DLC_VEGAS"); } else { string autoLoadPath = Path.Combine(dlcDir, "autoload.ini"); //CHECK IF FILE EXISTS? if (File.Exists(autoLoadPath)) { IniFile dlcAutoload = new IniFile(autoLoadPath); string name = Path.GetFileName(dlcDir); int mount = Convert.ToInt32(dlcAutoload.ReadValue("ME1DLCMOUNT", "ModMount")); dlcTable.Add(mount, name); } } } // ADD BASEGAME = 0 dlcTable.Add(0, "BioGame"); // 3. REMOVE ALL SEEKFREEPCPATHs/DLCMOVIEPATHS FROM $DOCUMENTS$\BIOWARE\MASS EFFECT\CONFIG\BIOENGINE.ini string userDocs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var bioEnginePath = Path.Combine(userDocs, "BioWare", "Mass Effect", "Config", "BIOEngine.ini"); try { File.SetAttributes(bioEnginePath, File.GetAttributes(bioEnginePath) & ~FileAttributes.ReadOnly); } catch (IOException e) { MessageBox.Show($"BioEngine not found. Run config or game to set it up. {ExceptionHandlerDialogWPF.FlattenException(e)}"); return; } var BioEngine = new IniFile(bioEnginePath); //Clean out seekfreepaths and moviepaths while (BioEngine.ReadValue("Core.System", "SeekFreePCPaths") != "") { BioEngine.RemoveKey("Core.System", "SeekFreePCPaths"); } while (BioEngine.ReadValue("Core.System", "DLC_MoviePaths") != "") { BioEngine.RemoveKey("Core.System", "DLC_MoviePaths"); } // 4. ADD SEEKFREE PATHS IN REVERSE ORDER (HIGHEST= BIOGAME, ETC). //SORT INTO REVERSE ORDER 0 => HIGHEST FOR BIOENGINE foreach (KeyValuePair <int, string> item in dlcTable.OrderBy(k => k.Key)) { if (item.Key == 0) { //The @"string\thing" allows you to use \ instead of \\. Very good if you are using paths. Though most times you should use Path.Combine() as it will prevent you missing one by accident BioEngine.WriteNewValue("Core.System", "SeekFreePCPaths", @"..\BioGame\CookedPC"); } else { BioEngine.WriteNewValue("Core.System", "SeekFreePCPaths", $@"..\DLC\{item.Value}\CookedPC"); if (Directory.Exists(Path.Combine(ME1Directory.DLCPath, item.Value, "Movies"))) { BioEngine.WriteNewValue("Core.System", "DLC_MoviePaths", $@"..\DLC\{item.Value}\Movies"); //Add MoviePath if present } } } // 5. BUILD FILEINDEX.TXT FILE FOR EACH DLC AND BASEGAME // BACKUP BASEGAME Fileindex.txt => Fileindex.bak if not done already. var fileIndexBackupFile = Path.Combine(ME1Directory.cookedPath, "FileIndex.bak"); if (!File.Exists(fileIndexBackupFile)) { //This might fail as the game will be installed into a write-protected directory for most users by default try { File.Copy(Path.Combine(ME1Directory.cookedPath, "FileIndex.txt"), fileIndexBackupFile); } catch (IOException e) { MessageBox.Show($"Error backup up FileIndex.txt:\n{ExceptionHandlerDialogWPF.FlattenException((e))}"); return; } } // CALL FUNCTION TO BUILD EACH FILEINDEX. START WITH HIGHEST DLC MOUNT -> ADD TO MASTER FILE LIST // DO NOT ADD DUPLICATES TOCTasks.ClearEx(); var masterList = new List <string>(); foreach (KeyValuePair <int, string> fileListStem in dlcTable.OrderByDescending(k => k.Key)) { if (fileListStem.Value == "BioGame") { //Using a list is pass by reference so our copy and the function's copy will be the same. //Note this does not work with primitive types like int (unless using the ref keyword), or immutable types like string. //(Immutable in c# = they can't be changed. modifying a string will return a new string instead) GenerateFileList(Path.Combine(ME1Directory.BioGamePath, "CookedPC"), masterList); } else { GenerateFileList(Path.Combine(ME1Directory.DLCPath, fileListStem.Value, "CookedPC"), masterList); } } //7. FINAL MESSAGE ON TOC TASKS TOCTasks.Add(new ListBoxTask { Header = "Done", Icon = EFontAwesomeIcon.Solid_Check, Foreground = Brushes.Green, Spinning = false }); }
private string relinkObjectProperty(IMEPackage importingPCC, IMEPackage destinationPCC, ObjectProperty objProperty, List <KeyValuePair <int, int> > crossPCCObjectMappingList) { if (objProperty.Value == 0) { return(null); //do not relink 0 } if (importingPCC == destinationPCC && objProperty.Value < 0) { return(null); //do not relink same-pcc imports. } int sourceObjReference = objProperty.Value; if (sourceObjReference > 0) { sourceObjReference--; //make 0 based for mapping. } if (sourceObjReference < 0) { sourceObjReference++; //make 0 based for mapping. } //if (objProperty.Name != null) //{ // Debug.WriteLine(objProperty.Name); //} KeyValuePair <int, int> mapping = crossPCCObjectMappingList.Where(pair => pair.Key == sourceObjReference).FirstOrDefault(); var defaultKVP = default(KeyValuePair <int, int>); //struct comparison if (!mapping.Equals(defaultKVP)) { //relink int newval = 0; if (mapping.Value > 0) { newval = mapping.Value + 1; //reincrement } else if (mapping.Value < 0) { newval = mapping.Value - 1; //redecrement } objProperty.Value = (newval); IEntry entry = destinationPCC.getEntry(newval); string s = ""; if (entry != null) { s = entry.GetFullPath; } Debug.WriteLine("Relink hit: " + sourceObjReference + objProperty.Name + ": " + s); } else if (objProperty.Value < 0) //It's an unmapped import { //objProperty is currently pointing to importingPCC as that is where we read the properties from int n = objProperty.Value; int origvalue = n; int importZeroIndex = Math.Abs(n) - 1; //Debug.WriteLine("Relink miss, attempting JIT relink on " + n + " " + rootNode.Text); if (n < 0 && importZeroIndex < importingPCC.ImportCount) { //Get the original import ImportEntry origImport = importingPCC.getImport(importZeroIndex); string origImportFullName = origImport.GetFullPath; //Debug.WriteLine("We should import " + origImport.GetFullPath); ImportEntry crossImport = null; string linkFailedDueToError = null; try { crossImport = getOrAddCrossImport(origImportFullName, importingPCC, destinationPCC); } catch (Exception e) { //Error during relink KFreonLib.Debugging.DebugOutput.StartDebugger("PCC Relinker"); DebugOutput.PrintLn("Exception occured during relink: "); DebugOutput.PrintLn(ExceptionHandlerDialogWPF.FlattenException(e)); DebugOutput.PrintLn("You may want to consider discarding this sessions' changes as relinking was not able to properly finish."); linkFailedDueToError = e.Message; } if (crossImport != null) { //cache item. Imports are stored +1, Exports-1. Someday I will go back and make this just 0 indexed crossPCCObjectMappingList.Add(new KeyValuePair <int, int>(sourceObjReference, crossImport.UIndex + 1)); //add to mapping to speed up future relinks objProperty.Value = crossImport.UIndex; Debug.WriteLine("Relink hit: Dynamic CrossImport for " + origvalue + " " + importingPCC.getEntry(origvalue).GetFullPath + " -> " + objProperty.Value); } else { if (linkFailedDueToError != null) { Debug.WriteLine("Relink failed: CrossImport porting failed for " + objProperty.Name + " " + objProperty.Value + ": " + importingPCC.getEntry(origvalue).GetFullPath); return("Relink failed for " + objProperty.Name + " " + objProperty.Value + ": " + linkFailedDueToError); } else if (destinationPCC.getEntry(objProperty.Value) != null) { Debug.WriteLine("Relink failed: CrossImport porting failed for " + objProperty.Name + " " + objProperty.Value + ": " + importingPCC.getEntry(origvalue).GetFullPath); return("Relink failed: CrossImport porting failed for " + objProperty.Name + " " + objProperty.Value + " " + destinationPCC.getEntry(objProperty.Value).GetFullPath); } else { return("Relink failed: New export does not exist - this is probably a bug in cross import code for " + objProperty.Name + " " + objProperty.Value); } } } } else { string path = importingPCC.getEntry(objProperty.Value) != null?importingPCC.getEntry(objProperty.Value).GetFullPath : "Entry not found: " + objProperty.Value; Debug.WriteLine("Relink failed: " + objProperty.Name + " " + objProperty.Value + " " + path); return("Relink failed: " + objProperty.Name + " " + objProperty.Value + " " + path); } return(null); }
private void saveByReconstructing(string path, bool isSaveAs) { try { if (exports.Any(exp => exp.ClassName == "Level")) { Flags |= EPackageFlags.Map; } //UDK does not like it when exports have the forced export flag, which is common in ME files foreach (ExportEntry export in exports) { //if (export.ClassName != "Package") { export.ExportFlags &= ~EExportFlags.ForcedExport; } } var ms = new MemoryStream(); //just for positioning. We write over this later when the header values have been updated WriteHeader(ms); //name table NameOffset = (int)ms.Position; NameCount = Gen0NameCount = names.Count; foreach (string name in names) { ms.WriteUnrealStringASCII(name); ms.WriteInt32(0); ms.WriteInt32(458768); } //import table ImportOffset = (int)ms.Position; ImportCount = imports.Count; foreach (ImportEntry e in imports) { ms.WriteFromBuffer(e.Header); } //export table ExportOffset = (int)ms.Position; ExportCount = Gen0NetworkedObjectCount = Gen0ExportCount = exports.Count; foreach (ExportEntry e in exports) { e.HeaderOffset = (uint)ms.Position; ms.WriteFromBuffer(e.Header); } //dependency table DependencyTableOffset = (int)ms.Position; ms.WriteZeros(4 * ExportCount); importExportGuidsOffset = (int)ms.Position; importGuidsCount = exportGuidsCount = 0; //generate thumbnails ThumbnailTable.Clear(); foreach (ExportEntry export in exports) { if (export.IsTexture()) { var tex = new Texture2D(export); var mip = tex.GetTopMip(); ThumbnailTable.Add(new Thumbnail { ClassName = export.ClassName, PathName = export.InstancedFullPath, Width = mip.width, Height = mip.height, Data = tex.GetPNG(mip) }); } } //write thumbnails foreach (Thumbnail thumbnail in ThumbnailTable) { thumbnail.Offset = (int)ms.Position; ms.WriteInt32(thumbnail.Width); ms.WriteInt32(thumbnail.Height); ms.WriteInt32(thumbnail.Data.Length); ms.WriteFromBuffer(thumbnail.Data); //File.WriteAllBytes(Path.Combine(Path.GetDirectoryName(FilePath), $"{thumbnail.PathName}({thumbnail.ClassName}).png"), thumbnail.Data); } thumbnailTableOffset = (int)ms.Position; ms.WriteInt32(ThumbnailTable.Count); foreach (Thumbnail thumbnail in ThumbnailTable) { ms.WriteUnrealStringASCII(thumbnail.ClassName); ms.WriteUnrealStringASCII(thumbnail.PathName); ms.WriteInt32(thumbnail.Offset); } FullHeaderSize = (int)ms.Position; //export data foreach (ExportEntry e in exports) { UpdateUDKOffsets(e, (int)ms.Position); e.DataOffset = (int)ms.Position; ms.WriteFromBuffer(e.Data); //update size and offset in already-written header long pos = ms.Position; ms.JumpTo(e.HeaderOffset + 32); ms.WriteInt32(e.DataSize); //DataSize might have been changed by UpdateOffsets ms.WriteInt32(e.DataOffset); ms.JumpTo(pos); } //re-write header with updated values ms.JumpTo(0); WriteHeader(ms); File.WriteAllBytes(path, ms.ToArray()); if (!isSaveAs) { AfterSave(); } } catch (Exception ex) when(!App.IsDebug) { MessageBox.Show($"Error saving {FilePath}:\n{ExceptionHandlerDialogWPF.FlattenException(ex)}"); } }
private void saveByReconstructing(string path, bool isSaveAs) { try { var ms = new MemoryStream(); //just for positioning. We write over this later when the header values have been updated WriteHeader(ms); //name table NameOffset = (int)ms.Position; NameCount = Gen0NameCount = names.Count; foreach (string name in names) { switch (Game) { case MEGame.ME1: ms.WriteUnrealStringASCII(name); ms.WriteInt32(0); ms.WriteInt32(458768); break; case MEGame.ME2: ms.WriteUnrealStringASCII(name); ms.WriteInt32(-14); break; case MEGame.ME3: ms.WriteUnrealStringUnicode(name); break; } } //import table ImportOffset = (int)ms.Position; ImportCount = imports.Count; foreach (ImportEntry e in imports) { ms.WriteFromBuffer(e.Header); } //export table ExportOffset = (int)ms.Position; ExportCount = Gen0ExportCount = exports.Count; foreach (ExportEntry e in exports) { e.HeaderOffset = (uint)ms.Position; ms.WriteFromBuffer(e.Header); } DependencyTableOffset = (int)ms.Position; ms.WriteInt32(0);//zero-count DependencyTable FullHeaderSize = ImportExportGuidsOffset = (int)ms.Position; //export data foreach (ExportEntry e in exports) { switch (Game) { case MEGame.ME1: UpdateME1Offsets(e, (int)ms.Position); break; case MEGame.ME2: UpdateME2Offsets(e, (int)ms.Position); break; case MEGame.ME3: UpdateME3Offsets(e, (int)ms.Position); break; } e.DataOffset = (int)ms.Position; ms.WriteFromBuffer(e.Data); //update size and offset in already-written header long pos = ms.Position; ms.JumpTo(e.HeaderOffset + 32); ms.WriteInt32(e.DataSize); //DataSize might have been changed by UpdateOffsets ms.WriteInt32(e.DataOffset); ms.JumpTo(pos); } //re-write header with updated values ms.JumpTo(0); WriteHeader(ms); File.WriteAllBytes(path, ms.ToArray()); if (!isSaveAs) { AfterSave(); } } catch (Exception ex) when(!App.IsDebug) { MessageBox.Show($"Error saving {FilePath}:\n{ExceptionHandlerDialogWPF.FlattenException(ex)}"); } }