Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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));
            }
        }