private void hb1_SelectionChanged(object sender, EventArgs e) { int start = (int)Interpreter_Hexbox.SelectionStart; int len = (int)Interpreter_Hexbox.SelectionLength; int size = (int)Interpreter_Hexbox.ByteProvider.Length; try { if (bytes != null && start != -1 && start < size) { string s = $"Byte: {bytes[start]}"; //if selection is same as size this will crash. if (start <= bytes.Length - 4) { int val = BitConverter.ToInt32(bytes, start); s += $", Int: {val}"; s += $", Float: {BitConverter.ToSingle(bytes, start)}"; if (pcc != null) { if (pcc.IsName(val)) { s += $", Name: {pcc.GetNameEntry(val)}"; } if (pcc.GetEntry(val) is ExportEntry exp) { s += $", Export: {exp.ObjectName.Instanced}"; } else if (pcc.GetEntry(val) is ImportEntry imp) { s += $", Import: {imp.ObjectName.Instanced}"; } } } s += $" | Start=0x{start:X8} "; if (len > 0) { s += $"Length=0x{len:X8} "; s += $"End=0x{(start + len - 1):X8}"; } StatusBar_LeftMostText.Text = s; } else { StatusBar_LeftMostText.Text = "Nothing Selected"; } } catch { // ignored } }
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 string GetEntryString(this IMEPackage pcc, int index) { if (index == 0) { return("Null"); } string retStr = "Entry not found"; IEntry coreRefEntry = pcc.GetEntry(index); if (coreRefEntry != null) { retStr = coreRefEntry is ImportEntry ? "[I] " : "[E] "; retStr += coreRefEntry.InstancedFullPath; } return(retStr); }
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); }
public static Class ConvertClass(UClass uClass, bool decompileBytecode, FileLib lib = null) { IMEPackage pcc = uClass.Export.FileRef; VariableType parent = new VariableType(pcc.GetEntry(uClass.SuperClass)?.ObjectName.Instanced ?? "object"); VariableType outer = new VariableType(pcc.GetEntry(uClass.OuterClass)?.ObjectName.Instanced ?? parent.Name); // TODO: components var interfaces = new List <VariableType>(); foreach ((UIndex interfaceUIndex, UIndex _) in uClass.Interfaces) { interfaces.Add(new VariableType(pcc.GetEntry(interfaceUIndex)?.ObjectName.Instanced ?? "UNK_INTERFACE")); } var Types = new List <VariableType>(); var Vars = new List <VariableDeclaration>(); var Funcs = new List <Function>(); var States = new List <State>(); var nextItem = uClass.Children; while (pcc.TryGetUExport(nextItem, out ExportEntry nextChild)) { var objBin = ObjectBinary.From(nextChild); switch (objBin) { case UConst uConst: Types.Add(new Const(uConst.Export.ObjectName.Instanced, uConst.Value) { Literal = new ClassOutlineParser(new TokenStream <string>(new StringLexer(uConst.Value))).ParseConstValue() }); nextItem = uConst.Next; break; case UEnum uEnum: Types.Add(ConvertEnum(uEnum)); nextItem = uEnum.Next; break; case UFunction uFunction: Funcs.Add(ConvertFunction(uFunction, uClass, decompileBytecode)); nextItem = uFunction.Next; break; case UProperty uProperty: Vars.Add(ConvertVariable(uProperty)); nextItem = uProperty.Next; break; case UScriptStruct uScriptStruct: Types.Add(ConvertStruct(uScriptStruct)); nextItem = uScriptStruct.Next; break; case UState uState: nextItem = uState.Next; States.Add(ConvertState(uState, uClass, decompileBytecode)); break; default: nextItem = 0; break; } } var propObject = pcc.GetUExport(uClass.Defaults); var defaultProperties = ConvertDefaultProperties(propObject); Class AST = new Class(uClass.Export.ObjectName.Instanced, parent, outer, uClass.ClassFlags, interfaces, Types, Vars, Funcs, States, defaultProperties) { ConfigName = uClass.ClassConfigName, Package = uClass.Export.Parent is null?Path.GetFileNameWithoutExtension(pcc.FilePath) : uClass.Export.ParentInstancedFullPath, }; // Ugly quick fix: foreach (var member in Types) { member.Outer = AST; } foreach (var member in Vars) { member.Outer = AST; } foreach (var member in Funcs) { member.Outer = AST; } foreach (var member in States) { member.Outer = AST; } var virtFuncLookup = new CaseInsensitiveDictionary <ushort>(); for (ushort i = 0; i < uClass.FullFunctionsList.Length; i++) { virtFuncLookup.Add(uClass.FullFunctionsList[i].GetEntry(pcc)?.ObjectName, i); } AST.VirtualFunctionLookup = virtFuncLookup; return(AST); }
private BytecodeToken ReadNextInternal() { int readerpos = (int)_reader.BaseStream.Position; ME1OpCodes b = (ME1OpCodes)_reader.ReadByte(); switch (b) { case ME1OpCodes.EX_LocalVariable: case ME1OpCodes.EX_InstanceVariable: case ME1OpCodes.EX_NativeParm: return(ReadRef(r => r.ObjectName.Instanced)); case ME1OpCodes.EX_DefaultVariable: return(ReadRef(r => $"Default.{r.ObjectName.Instanced}")); case ME1OpCodes.EX_Return: { BytecodeToken returnValue = ReadNext(); return(new ReturnToken(returnValue, readerpos)); } case ME1OpCodes.EX_Assert: { _reader.ReadInt16(); _reader.ReadByte(); return(WrapNextBytecode(c => new BytecodeToken($"assert({c})", readerpos))); } case ME1OpCodes.EX_Switch: { byte b1 = _reader.ReadByte(); BytecodeToken switchExpr = ReadNext(); return(new SwitchToken(switchExpr.ToString(), switchExpr, readerpos)); } case ME1OpCodes.EX_Case: { short offset = _reader.ReadInt16(); if (offset == -1) { return(new DefaultToken(readerpos)); } BytecodeToken caseExpr = ReadNext(); return(new CaseToken(caseExpr.ToString(), readerpos)); } case ME1OpCodes.EX_Jump: { int offset = _reader.ReadInt16(); return(new UncondJumpToken(offset, readerpos)); } case ME1OpCodes.EX_JumpIfNot: { short offset = _reader.ReadInt16(); BytecodeToken condition = ReadNext(); if (IsInvalid(condition)) { return(WrapErrToken("if (!" + condition, condition)); } return(new JumpIfNotToken(offset, condition, readerpos)); } case ME1OpCodes.EX_LabelTable: { var token = new LabelTableToken(readerpos); while (true) { string labelName = ReadName(); if (labelName == "None") { break; } int offset = _reader.ReadInt32(); token.AddLabel(labelName, offset); } return(token); } case ME1OpCodes.EX_GotoLabel: return(WrapNextBytecode(op => Token("goto " + op, readerpos))); case ME1OpCodes.EX_Self: return(Token("self", readerpos)); case ME1OpCodes.EX_Skip: _reader.ReadInt16(); //Returning readnext causes a new token to be read return(ReadNext()); case ME1OpCodes.EX_EatReturnValue: _reader.ReadInt32(); return(ReadNext()); case ME1OpCodes.EX_Nothing: return(new NothingToken(readerpos)); case ME1OpCodes.EX_Stop: _reader.ReadInt16(); return(new NothingToken(readerpos)); case ME1OpCodes.EX_IntZero: return(Token("0", readerpos)); case ME1OpCodes.EX_IntOne: return(Token("1", readerpos)); case ME1OpCodes.EX_True: return(Token("true", readerpos)); case ME1OpCodes.EX_False: return(Token("false", readerpos)); case ME1OpCodes.EX_NoObject: case ME1OpCodes.EX_EmptyDelegate: return(Token("None", readerpos)); case ME1OpCodes.EX_Let: case ME1OpCodes.EX_LetBool: case ME1OpCodes.EX_LetDelegate: BytecodeToken lhs = ReadNext(); if (IsInvalid(lhs)) { return(lhs); } BytecodeToken rhs = ReadNext(); if (IsInvalid(rhs)) { return(WrapErrToken(lhs + " = " + rhs, rhs)); } return(Token(lhs + " = " + rhs, readerpos)); case ME1OpCodes.EX_IntConst: return(Token(_reader.ReadInt32().ToString(), readerpos)); case ME1OpCodes.EX_FloatConst: return(Token(_reader.ReadSingle().ToString(), readerpos)); case ME1OpCodes.EX_StringConst: { var s = ReadAsciiz().Replace("\n", "\\n").Replace("\t", "\\t"); return(Token($"\"{s}\"", readerpos)); } case ME1OpCodes.EX_ByteConst: case ME1OpCodes.EX_IntConstByte: return(Token(_reader.ReadByte().ToString(), readerpos)); case ME1OpCodes.EX_ObjectConst: { int objectIndex = _reader.ReadInt32(); var item = _package.GetEntry(objectIndex); if (item == null) { return(ErrToken("Unresolved class item " + objectIndex)); } return(Token($"{item.ClassName}'{item.ObjectName.Instanced}'", readerpos)); } case ME1OpCodes.EX_NameConst: return(Token($"'{ReadName()}'", readerpos)); case ME1OpCodes.EX_EndFunctionParms: return(new EndParmsToken(")", readerpos)); case ME1OpCodes.EX_ClassContext: case ME1OpCodes.EX_Context: { var context = ReadNext(); if (IsInvalid(context)) { return(context); } int exprSize = _reader.ReadInt16(); int bSize = _reader.ReadByte(); var value = ReadNext(); if (IsInvalid(value)) { return(WrapErrToken($"{context}.{value}", value)); } return(Token($"{context}.{value}", readerpos)); } case ME1OpCodes.EX_InterfaceContext: return(ReadNext()); case ME1OpCodes.EX_FinalFunction: { int functionIndex = _reader.ReadInt32(); var item = _package.GetEntry(functionIndex); if (item == null) { return(ErrToken("Unresolved function item " + item)); } string functionName = item.ObjectName.Instanced; return(ReadCall(functionName)); } case ME1OpCodes.EX_PrimitiveCast: { var prefix = _reader.ReadByte(); var v = ReadNext(); return(v); } case ME1OpCodes.EX_VirtualFunction: return(ReadCall(ReadName())); case ME1OpCodes.EX_GlobalFunction: return(ReadCall("Global." + ReadName())); case ME1OpCodes.EX_BoolVariable: return(ReadNext()); case ME1OpCodes.EX_ByteToInt: int objectRefIdx = _reader.ReadInt32(); if (_package.IsEntry(objectRefIdx)) { return(Token($"ByteToInt({_package.getObjectName(objectRefIdx)})", readerpos)); } else { return(Token($"ByteToInt(Unknown reference {objectRefIdx})", readerpos)); } case ME1OpCodes.EX_DynamicCast: { int typeIndex = _reader.ReadInt32(); var item = _package.GetEntry(typeIndex); return(WrapNextBytecode(op => Token($"{item.ObjectName.Instanced}({op})", readerpos))); } case ME1OpCodes.EX_Metacast: { int typeIndex = _reader.ReadInt32(); var item = _package.GetEntry(typeIndex); if (item == null) { return(ErrToken("Unresolved class item " + typeIndex)); } return(WrapNextBytecode(op => Token($"Class<{item.ObjectName.Instanced}>({op})", readerpos))); } case ME1OpCodes.EX_StructMember: { var field = ReadRef(); var structType = ReadRef(); int wSkip = _reader.ReadInt16(); var token = ReadNext(); if (IsInvalid(token)) { return(token); } return(Token($"{token}.{field.ObjectName.Instanced}", readerpos)); } case ME1OpCodes.EX_ArrayElement: case ME1OpCodes.EX_DynArrayElement: { var index = ReadNext(); if (IsInvalid(index)) { return(index); } var array = ReadNext(); if (IsInvalid(array)) { return(array); } return(Token($"{array}[{index}]", readerpos)); } case ME1OpCodes.EX_DynArrayLength: return(WrapNextBytecode(op => Token($"{op}.Length", readerpos))); case ME1OpCodes.EX_StructCmpEq: return(CompareStructs("==")); case ME1OpCodes.EX_StructCmpNe: return(CompareStructs("!=")); case ME1OpCodes.EX_EndOfScript: return(new EndOfScriptToken(readerpos)); case ME1OpCodes.EX_EmptyParmValue: case ME1OpCodes.EX_GoW_DefaultValue: return(new DefaultValueToken("", readerpos)); case ME1OpCodes.EX_DefaultParmValue: { var size = _reader.ReadInt16(); var offset = _reader.BaseStream.Position; var defaultValueExpr = ReadNext(); _reader.BaseStream.Position = offset + size; return(new DefaultParamValueToken(defaultValueExpr.ToString(), readerpos)); } case ME1OpCodes.EX_LocalOutVariable: int valueIndex = _reader.ReadInt32(); var packageItem = _package.GetEntry(valueIndex); if (packageItem == null) { return(ErrToken("Unresolved package item " + packageItem)); } return(Token(packageItem.ObjectName.Instanced, readerpos)); case ME1OpCodes.EX_Iterator: var expr = ReadNext(); int loopEnd = _reader.ReadInt16(); if (IsInvalid(expr)) { return(WrapErrToken("foreach " + expr, expr)); } return(new ForeachToken(loopEnd, expr, readerpos)); case ME1OpCodes.EX_IteratorPop: return(new IteratorPopToken(readerpos)); case ME1OpCodes.EX_IteratorNext: return(new IteratorNextToken(readerpos)); case ME1OpCodes.EX_New: var outer = ReadNext(); if (IsInvalid(outer)) { return(outer); } var name = ReadNext(); if (IsInvalid(name)) { return(name); } var flags = ReadNext(); if (IsInvalid(flags)) { return(flags); } var cls = ReadNext(); if (IsInvalid(cls)) { return(cls); } return(Token($"new({JoinTokens(outer, name, flags, cls)})", readerpos)); case ME1OpCodes.EX_VectorConst: var f1 = _reader.ReadSingle(); var f2 = _reader.ReadSingle(); var f3 = _reader.ReadSingle(); return(Token($"vect({f1},{f2},{f3})", readerpos)); case ME1OpCodes.EX_RotationConst: var i1 = _reader.ReadInt32(); var i2 = _reader.ReadInt32(); var i3 = _reader.ReadInt32(); return(Token($"rot({i1},{i2},{i3})", readerpos)); case ME1OpCodes.EX_InterfaceCast: { var interfaceName = ReadRef(); return(WrapNextBytecode(op => Token($"{interfaceName.ObjectName.Instanced}({op})", readerpos))); } case ME1OpCodes.EX_Conditional: { var condition = ReadNext(); if (IsInvalid(condition)) { return(condition); } var trueSize = _reader.ReadInt16(); var pos = _reader.BaseStream.Position; var truePart = ReadNext(); if (IsInvalid(truePart)) { return(WrapErrToken($"{condition} ? {truePart}", truePart)); } if (_reader.BaseStream.Position != pos + trueSize) { return(ErrToken("conditional true part size mismatch")); } var falseSize = _reader.ReadInt16(); pos = _reader.BaseStream.Position; var falsePart = ReadNext(); if (IsInvalid(truePart)) { return(WrapErrToken($"{condition} ? {truePart} : {falsePart}", falsePart)); } Debug.Assert(_reader.BaseStream.Position == pos + falseSize); return(Token($"{condition} ? {truePart} : {falsePart}", readerpos)); } case ME1OpCodes.EX_DynArrayFind: return(ReadDynArray1ArgMethod("Find")); case ME1OpCodes.EX_DynArrayFindStruct: return(ReadDynArray2ArgMethod("Find", true)); case ME1OpCodes.EX_DynArrayRemove: return(ReadDynArray2ArgMethod("Remove", false)); case ME1OpCodes.EX_DynArrayInsert: return(ReadDynArray2ArgMethod("Insert", false)); case ME1OpCodes.EX_DynArrayAddItem: return(ReadDynArray1ArgMethod("AddItem")); case ME1OpCodes.EX_DynArrayRemoveItem: return(ReadDynArray1ArgMethod("RemoveItem")); case ME1OpCodes.EX_DynArrayInsertItem: return(ReadDynArray2ArgMethod("InsertItem", true)); case ME1OpCodes.EX_DynArrayIterator: { var array = ReadNext(); if (IsInvalid(array)) { return(array); } var iteratorVar = ReadNext(); if (IsInvalid(iteratorVar)) { return(iteratorVar); } _reader.ReadInt16(); var endOffset = _reader.ReadInt16(); return(new ForeachToken(endOffset, array, iteratorVar, readerpos)); } case ME1OpCodes.EX_DelegateProperty: case ME1OpCodes.EX_InstanceDelegate: return(Token(ReadName(), readerpos)); case ME1OpCodes.EX_DelegateFunction: { var receiver = ReadNext(); if (IsInvalid(receiver)) { return(receiver); } var methodName = ReadName(); if (receiver.ToString().StartsWith("__") && receiver.ToString().EndsWith("__Delegate")) { return(ReadCall(methodName)); } return(ReadCall(receiver + "." + methodName)); } case ME1OpCodes.EX_EqualEqual_DelDel: case ME1OpCodes.EX_EqualEqual_DelFunc: return(CompareDelegates("==")); case ME1OpCodes.EX_NotEqual_DelDel: return(CompareDelegates("!=")); default: if ((int)b >= 0x60) { return(ReadNativeCall((byte)b)); } return(ErrToken("// unknown bytecode " + ((byte)b).ToString("X2"), (int)b)); } }
public IEntry GetEntry(IMEPackage pcc) => pcc.GetEntry(value);
/// <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); } }
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 static HashSet <int> GetReferencedEntries(this IMEPackage pcc, bool getreferenced = true, bool getactorrefs = false, ExportEntry startatexport = null) { var result = new HashSet <int>(); Level level = null; Stack <IEntry> entriesToEvaluate = new Stack <IEntry>(); HashSet <IEntry> entriesEvaluated = new HashSet <IEntry>(); HashSet <IEntry> entriesReferenced = new HashSet <IEntry>(); if (startatexport != null) //Start at object { entriesToEvaluate.Push(startatexport); entriesReferenced.Add(startatexport); entriesEvaluated.Add(pcc.GetUExport(startatexport.idxLink)); //Do not go up the chain if parsing an export } else if (pcc.Exports.FirstOrDefault(exp => exp.ClassName == "Level") is ExportEntry levelExport) //Evaluate level with only actors, model+components, sequences and level class being processed. { level = ObjectBinary.From <Level>(levelExport); entriesEvaluated.Add(null); //null stops future evaluations entriesEvaluated.Add(levelExport); entriesReferenced.Add(levelExport); var levelclass = levelExport.Class; entriesToEvaluate.Push(levelclass); entriesReferenced.Add(levelclass); foreach (int actoridx in level.Actors) { var actor = pcc.GetEntry(actoridx); entriesToEvaluate.Push(actor); entriesReferenced.Add(actor); } var model = pcc.GetEntry(level.Model?.value ?? 0); entriesToEvaluate.Push(model); entriesReferenced.Add(model); foreach (var comp in level.ModelComponents) { var compxp = pcc.GetEntry(comp); entriesToEvaluate.Push(compxp); entriesReferenced.Add(compxp); } foreach (var seq in level.GameSequences) { var seqxp = pcc.GetEntry(seq); entriesToEvaluate.Push(seqxp); entriesReferenced.Add(seqxp); } var localpackage = pcc.Exports.FirstOrDefault(x => x.ClassName == "Package" && x.ObjectName.ToString().ToLower() == Path.GetFileNameWithoutExtension(pcc.FilePath).ToLower()); // Make sure world, localpackage, shadercache are all marked as referenced. entriesToEvaluate.Push(localpackage); entriesReferenced.Add(localpackage); var world = levelExport.Parent; entriesToEvaluate.Push(world); entriesReferenced.Add(world); var shadercache = pcc.Exports.FirstOrDefault(x => x.ClassName == "ShaderCache"); if (shadercache != null) { entriesEvaluated.Add(shadercache); entriesReferenced.Add(shadercache); entriesToEvaluate.Push(shadercache.Class); entriesReferenced.Add(shadercache.Class); } } else { return(result); //If this has no level it is a reference / seekfree package and shouldn't be compacted. } var theserefs = new HashSet <IEntry>(); while (!entriesToEvaluate.IsEmpty()) { var ent = entriesToEvaluate.Pop(); try { if (entriesEvaluated.Contains(ent) || (ent?.UIndex ?? 0) == 0 || (getactorrefs && !ent.InstancedFullPath.Contains("PersistentLevel"))) { continue; } entriesEvaluated.Add(ent); if (ent.idxLink != 0) { theserefs.Add(pcc.GetEntry(ent.idxLink)); } if (ent.UIndex < 0) { continue; } var exp = pcc.GetUExport(ent.UIndex); //find header references only if doing non-actors if (!getactorrefs) { if ((exp.Archetype?.UIndex ?? 0) != 0) { theserefs.Add(exp.Archetype); } if ((exp.Class?.UIndex ?? 0) != 0) { theserefs.Add(exp.Class); } if ((exp.SuperClass?.UIndex ?? 0) != 0) { theserefs.Add(exp.SuperClass); } if (exp.HasComponentMap) { foreach (var kvp in exp.ComponentMap) { //theserefs.Add(pcc.GetEntry(kvp.Value)); //THIS IS INCORRECT SHOULD NOT BE ON UINDEX } } } else { exp.CondenseArchetypes(); } //find property references findPropertyReferences(exp.GetProperties(), exp); //find binary references if (!exp.IsDefaultObject && ObjectBinary.From(exp) is ObjectBinary objBin) { List <(UIndex, string)> indices = objBin.GetUIndexes(exp.FileRef.Game); foreach ((UIndex uIndex, string propName) in indices) { if (uIndex != exp.UIndex) { theserefs.Add(pcc.GetEntry(uIndex)); } } } foreach (var reference in theserefs) { if (!entriesEvaluated.Contains(reference)) { entriesToEvaluate.Push(reference); entriesReferenced.Add(reference); } } theserefs.Clear(); } catch (Exception e) { Console.WriteLine($"Error getting references {ent.UIndex} {ent.ObjectName.Instanced}: {e.Message}"); } } if (getreferenced) { foreach (var entry in entriesReferenced) { result.Add(entry?.UIndex ?? 0); } } else { foreach (var xp in pcc.Exports) { if (!entriesReferenced.Contains(xp)) { result.Add(xp?.UIndex ?? 0); } } foreach (var im in pcc.Imports) { if (!entriesReferenced.Contains(im)) { result.Add(im?.UIndex ?? 0); } } } return(result); void findPropertyReferences(PropertyCollection props, ExportEntry exp) { foreach (Property prop in props) { switch (prop) { case ObjectProperty objectProperty: if (objectProperty.Value != 0 && objectProperty.Value != exp.UIndex) { theserefs.Add(pcc.GetEntry(objectProperty.Value)); } break; case DelegateProperty delegateProperty: if (delegateProperty.Value.Object != 0 && delegateProperty.Value.Object != exp.UIndex) { theserefs.Add(pcc.GetEntry(delegateProperty.Value.Object)); } break; case StructProperty structProperty: findPropertyReferences(structProperty.Properties, exp); break; case ArrayProperty <ObjectProperty> arrayProperty: for (int i = 0; i < arrayProperty.Count; i++) { ObjectProperty objProp = arrayProperty[i]; if (objProp.Value != 0 && objProp.Value != exp.UIndex) { theserefs.Add(pcc.GetEntry(objProp.Value)); } } break; case ArrayProperty <StructProperty> arrayProperty: for (int i = 0; i < arrayProperty.Count; i++) { StructProperty structProp = arrayProperty[i]; findPropertyReferences(structProp.Properties, exp); } break; } } } }
public static PropertyCollection RemoveIncompatibleProperties(IMEPackage sourcePcc, PropertyCollection props, string typeName, MEGame newGame) { var infoProps = UnrealObjectInfo.GetAllProperties(newGame, typeName); var newProps = new PropertyCollection(); foreach (UProperty prop in props) { if (infoProps.ContainsKey(prop.Name)) { switch (prop) { case ArrayProperty <DelegateProperty> adp: //don't think these exist? if they do, delete them break; case ArrayProperty <EnumProperty> aep: if (UnrealObjectInfo.GetEnumValues(newGame, aep.Reference) is List <NameReference> enumValues) { foreach (EnumProperty enumProperty in aep) { if (!enumValues.Contains(enumProperty.Value)) { enumProperty.Value = enumValues.First(); //hope that the first value is a reasonable default } } newProps.Add(aep); } break; case ArrayProperty <ObjectProperty> asp: for (int i = asp.Count - 1; i >= 0; i--) { if (asp[i].Value == 0 || sourcePcc.GetEntry(asp[i].Value) is IEntry entry && !entry.FullPath.StartsWith(UnrealPackageFile.TrashPackageName)) { continue; } //delete if it references a trashed entry or if value is invalid asp.RemoveAt(i); } newProps.Add(asp); break; case ArrayProperty <StructProperty> asp: if (UnrealObjectInfo.GetStructs(newGame).ContainsKey(asp.Reference)) { if (HasIncompatibleImmutabilities(asp.Reference, out bool newImmutability)) { break; } foreach (StructProperty structProperty in asp) { structProperty.Properties = RemoveIncompatibleProperties(sourcePcc, structProperty.Properties, structProperty.StructType, newGame); structProperty.IsImmutable = newImmutability; } newProps.Add(asp); } break; case DelegateProperty delegateProperty: //script related, so just delete it. break; case EnumProperty enumProperty: if (UnrealObjectInfo.GetEnumValues(newGame, enumProperty.EnumType) is List <NameReference> values) { if (!values.Contains(enumProperty.Value)) { enumProperty.Value = values.First(); //hope that the first value is a reasonable default } newProps.Add(enumProperty); } break; case ObjectProperty objectProperty: { if (objectProperty.Value == 0 || sourcePcc.GetEntry(objectProperty.Value) is IEntry entry && !entry.FullPath.StartsWith(UnrealPackageFile.TrashPackageName)) { newProps.Add(objectProperty); } break; } case StructProperty structProperty: string structType = structProperty.StructType; if (UnrealObjectInfo.GetStructs(newGame).ContainsKey(structType)) { if (HasIncompatibleImmutabilities(structType, out bool newImmutability)) { break; } structProperty.Properties = RemoveIncompatibleProperties(sourcePcc, structProperty.Properties, structType, newGame); structProperty.IsImmutable = newImmutability; newProps.Add(structProperty); } break; default: newProps.Add(prop); break; } } } return(newProps); bool HasIncompatibleImmutabilities(string structType, out bool newImmutability) { bool sourceIsImmutable = UnrealObjectInfo.IsImmutable(structType, sourcePcc.Game); newImmutability = UnrealObjectInfo.IsImmutable(structType, newGame); if (sourceIsImmutable && newImmutability && !UnrealObjectInfo.GetClassOrStructInfo(sourcePcc.Game, structType).properties .SequenceEqual(UnrealObjectInfo.GetClassOrStructInfo(newGame, structType).properties)) { //both immutable, but have different properties return(true); } if (!sourceIsImmutable && newImmutability) { //can't easily guarantee it will have have all neccesary properties return(true); } return(false); } }
/// <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); }
public static void ScanStuff(PackageEditorWPF pewpf) { //var filePaths = MELoadedFiles.GetOfficialFiles(MEGame.ME3);//.Concat(MELoadedFiles.GetOfficialFiles(MEGame.ME2));//.Concat(MELoadedFiles.GetOfficialFiles(MEGame.ME1)); //var filePaths = MELoadedFiles.GetAllFiles(game); /*"Core.pcc", "Engine.pcc", "GameFramework.pcc", "GFxUI.pcc", "WwiseAudio.pcc", "SFXOnlineFoundation.pcc", "SFXGame.pcc" */ var filePaths = new[] { "Core.pcc", "Engine.pcc", "GameFramework.pcc", "GFxUI.pcc", "WwiseAudio.pcc", "SFXOnlineFoundation.pcc" }.Select(f => Path.Combine(ME3Directory.CookedPCPath, f)); var interestingExports = new List <EntryStringPair>(); var foundClasses = new HashSet <string>(); //new HashSet<string>(BinaryInterpreterWPF.ParsableBinaryClasses); var foundProps = new Dictionary <string, string>(); var unkOpcodes = new List <int>();//Enumerable.Range(0x5B, 8).ToList(); unkOpcodes.Add(0); unkOpcodes.Add(1); var unkOpcodesInfo = unkOpcodes.ToDictionary(i => i, i => new OpcodeInfo()); var comparisonDict = new Dictionary <string, (byte[] original, byte[] newData)>(); var extraInfo = new HashSet <string>(); pewpf.IsBusy = true; pewpf.BusyText = "Scanning"; Task.Run(() => { //preload base files for faster scanning using var baseFiles = MEPackageHandler.OpenMEPackages(EntryImporter.FilesSafeToImportFrom(MEGame.ME3) .Select(f => Path.Combine(ME3Directory.CookedPCPath, f))); baseFiles.Add( MEPackageHandler.OpenMEPackage(Path.Combine(ME3Directory.CookedPCPath, "BIOP_MP_COMMON.pcc"))); foreach (string filePath in filePaths) { //ScanShaderCache(filePath); //ScanMaterials(filePath); //ScanStaticMeshComponents(filePath); //ScanLightComponents(filePath); //ScanLevel(filePath); //if (findClass(filePath, "ShaderCache", true)) break; //findClassesWithBinary(filePath); ScanScripts2(filePath); //if (interestingExports.Count > 0) //{ // break; //} //if (resolveImports(filePath)) break; } }).ContinueWithOnUIThread(prevTask => { pewpf.IsBusy = false; interestingExports.Add(new EntryStringPair(null, string.Join("\n", extraInfo))); var listDlg = new ListDialog(interestingExports, "Interesting Exports", "", pewpf) { DoubleClickEntryHandler = entryItem => { if (entryItem?.Entry is IEntry entryToSelect) { PackageEditorWPF p = new PackageEditorWPF(); p.Show(); p.LoadFile(entryToSelect.FileRef.FilePath, entryToSelect.UIndex); p.Activate(); if (comparisonDict.TryGetValue($"{entryToSelect.UIndex} {entryToSelect.FileRef.FilePath}", out (byte[] original, byte[] newData)val)) { File.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "original.bin"), val.original); File.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "new.bin"), val.newData); } } } }; listDlg.Show(); }); #region extra scanning functions bool findClass(string filePath, string className, bool withBinary = false) { Debug.WriteLine($" {filePath}"); using (IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath)) { //if (!pcc.IsCompressed) return false; var exports = pcc.Exports.Where(exp => !exp.IsDefaultObject && exp.IsA(className)); foreach (ExportEntry exp in exports) { try { //Debug.WriteLine($"{exp.UIndex}: {filePath}"); var originalData = exp.Data; exp.WriteBinary(ObjectBinary.From(exp)); var newData = exp.Data; if (!originalData.SequenceEqual(newData)) { interestingExports.Add(exp); File.WriteAllBytes( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "original.bin"), originalData); File.WriteAllBytes( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "new.bin"), newData); return(true); } } catch (Exception exception) { Console.WriteLine(exception); interestingExports.Add(new EntryStringPair(exp, $"{exception}")); return(true); } } } return(false); } void findClassesWithBinary(string filePath) { using (IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath)) { foreach (ExportEntry exp in pcc.Exports.Where(exp => !exp.IsDefaultObject)) { try { if (!foundClasses.Contains(exp.ClassName) && exp.propsEnd() < exp.DataSize) { if (ObjectBinary.From(exp) != null) { foundClasses.Add(exp.ClassName); } else if (exp.GetBinaryData().Any(b => b != 0)) { foundClasses.Add(exp.ClassName); interestingExports.Add(exp); } } } catch (Exception exception) { Console.WriteLine(exception); interestingExports.Add(new EntryStringPair(exp, $"{exp.UIndex}: {filePath}\n{exception}")); } } } } void ScanShaderCache(string filePath) { using (IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath)) { ExportEntry shaderCache = pcc.Exports.FirstOrDefault(exp => exp.ClassName == "ShaderCache"); if (shaderCache == null) { return; } int oldDataOffset = shaderCache.DataOffset; try { MemoryStream binData = new MemoryStream(shaderCache.Data); binData.JumpTo(shaderCache.propsEnd() + 1); int nameList1Count = binData.ReadInt32(); binData.Skip(nameList1Count * 12); int namelist2Count = binData.ReadInt32(); //namelist2 binData.Skip(namelist2Count * 12); int shaderCount = binData.ReadInt32(); for (int i = 0; i < shaderCount; i++) { binData.Skip(24); int nextShaderOffset = binData.ReadInt32() - oldDataOffset; binData.Skip(14); if (binData.ReadInt32() != 1111577667) //CTAB { interestingExports.Add(new EntryStringPair(null, $"{binData.Position - 4}: {filePath}")); return; } binData.JumpTo(nextShaderOffset); } int vertexFactoryMapCount = binData.ReadInt32(); binData.Skip(vertexFactoryMapCount * 12); int materialShaderMapCount = binData.ReadInt32(); for (int i = 0; i < materialShaderMapCount; i++) { binData.Skip(16); int switchParamCount = binData.ReadInt32(); binData.Skip(switchParamCount * 32); int componentMaskParamCount = binData.ReadInt32(); //if (componentMaskParamCount != 0) //{ // interestingExports.Add($"{i}: {filePath}"); // return; //} binData.Skip(componentMaskParamCount * 44); int normalParams = binData.ReadInt32(); if (normalParams != 0) { interestingExports.Add(new EntryStringPair(null, $"{i}: {filePath}")); return; } binData.Skip(normalParams * 29); int unrealVersion = binData.ReadInt32(); int licenseeVersion = binData.ReadInt32(); if (unrealVersion != 684 || licenseeVersion != 194) { interestingExports.Add(new EntryStringPair(null, $"{binData.Position - 8}: {filePath}")); return; } int nextMaterialShaderMapOffset = binData.ReadInt32() - oldDataOffset; binData.JumpTo(nextMaterialShaderMapOffset); } } catch (Exception exception) { Console.WriteLine(exception); interestingExports.Add(new EntryStringPair(null, $"{filePath}\n{exception}")); } } } void ScanScripts(string filePath) { using IMEPackage pcc = MEPackageHandler.OpenMEPackage(filePath); foreach (ExportEntry exp in pcc.Exports.Where(exp => !exp.IsDefaultObject)) { try { if ((exp.ClassName == "State" || exp.ClassName == "Function") && ObjectBinary.From(exp) is UStruct uStruct) { byte[] data = exp.Data; (_, List <BytecodeSingularToken> tokens) = Bytecode.ParseBytecode(uStruct.ScriptBytes, exp); foreach (var token in tokens) { if (token.CurrentStack.Contains("UNKNOWN") || token.OpCodeString.Contains("UNKNOWN")) { interestingExports.Add(exp); } if (unkOpcodes.Contains(token.OpCode)) { int refUIndex = EndianReader.ToInt32(data, token.StartPos + 1, pcc.Endian); IEntry entry = pcc.GetEntry(refUIndex); if (entry != null && (entry.ClassName == "ByteProperty")) { var info = unkOpcodesInfo[token.OpCode]; info.Usages.Add(pcc.FilePath, exp.UIndex, token.StartPos); info.PropTypes.Add(refUIndex switch { 0 => "Null", _ when entry != null => entry.ClassName, _ => "Invalid" }); if (entry != null) { if (entry.Parent == exp) { info.PropLocations.Add("Local"); } else if (entry.Parent == (exp.Parent.ClassName == "State" ? exp.Parent.Parent : exp.Parent)) { info.PropLocations.Add("ThisClass"); } else if (entry.Parent.ClassName == "Function") { info.PropLocations.Add("OtherFunction"); } else if (exp.Parent.IsA(entry.Parent.ObjectName)) { info.PropLocations.Add("AncestorClass"); } else { info.PropLocations.Add("OtherClass"); } } } } }
private static EntryStringPair relinkUIndex(IMEPackage importingPCC, ExportEntry relinkingExport, ref int uIndex, string propertyName, OrderedMultiValueDictionary <IEntry, IEntry> crossPCCObjectMappingList, string prefix, bool importExportDependencies = false, RelinkerCache relinkerCache = null) { 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, relinkerCache: relinkerCache); } catch (Exception e) { //Error during relink 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(new EntryStringPair(relinkingExport, $"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(new EntryStringPair(relinkingExport, $"Relink failed: CrossImport porting failed for {prefix}{propertyName} {uIndex} {destinationPcc.GetEntry(uIndex).FullPath} in export {relinkingExport.FullPath}({relinkingExport.UIndex})")); } return(new EntryStringPair(relinkingExport, $"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 { bool importingFromGlobalFile = false; //It's an export //Attempt lookup ExportEntry sourceExport = importingPCC.GetUExport(uIndex); string instancedFullPath = sourceExport.InstancedFullPath; string sourceFilePath = sourceExport.FileRef.FilePath; if (EntryImporter.IsSafeToImportFrom(sourceFilePath, destinationPcc.Game)) { importingFromGlobalFile = true; instancedFullPath = $"{Path.GetFileNameWithoutExtension(sourceFilePath)}.{instancedFullPath}"; } IEntry existingEntry = null; if (relinkerCache != null) { relinkerCache.destInstancedFullPathToEntryMap.TryGetValue(instancedFullPath, out existingEntry); } else { existingEntry = destinationPcc.Exports.FirstOrDefault(x => x.InstancedFullPath == instancedFullPath); existingEntry ??= destinationPcc.Imports.FirstOrDefault(x => x.InstancedFullPath == instancedFullPath); } 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 (importingFromGlobalFile) { uIndex = EntryImporter.GetOrAddCrossImportOrPackageFromGlobalFile(sourceExport.FullPath, importingPCC, destinationPcc, crossPCCObjectMappingList, relinkerCache: relinkerCache).UIndex; } else { if (!crossPCCObjectMappingList.TryGetValue(sourceExport.Parent, out IEntry parent)) { parent = EntryImporter.GetOrAddCrossImportOrPackage(sourceExport.ParentFullPath, importingPCC, destinationPcc, true, crossPCCObjectMappingList, relinkerCache: relinkerCache); } ExportEntry importedExport = EntryImporter.ImportExport(destinationPcc, sourceExport, parent?.UIndex ?? 0, true, crossPCCObjectMappingList, relinkerCache: relinkerCache); 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(new EntryStringPair(relinkingExport, $"Relink failed: {prefix}{propertyName} {uIndex} in export {relinkingExport.FullPath}({relinkingExport.UIndex})")); } } return(null); }