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.GetIndexedFullPath; } return(retStr); }
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); }
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.GetFullPath.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.GetFullPath.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); } }
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)); case ME1OpCodes.EX_DefaultVariable: return(ReadRef(r => "Default." + r.ObjectName)); 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 + "'", readerpos)); } case ME1OpCodes.EX_NameConst: return(Token("'" + _package.getNameEntry((int)_reader.ReadInt64()) + "'", 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; 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 + "(" + 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 + ">(" + 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, 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, 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 + "(" + 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)); } }