Пример #1
0
        private static string GetCsTypeRecursive(string input, List <string> customenums)
        {
            if (input.Contains("array")) // TODO: support for more generics?
            {
                string returntype = input;

                // array types
                // [Ordinal(18)] [RED("editorCachedIkEffectorsID", 2, 0)] public CArray<CInt32> EditorCachedIkEffectorsID { get; set; }
                var regarray     = new Regex(@"(?:.*)array\s*<\s*(?<TYPE>\w+)\s*>.*");
                var matchIsArray = regarray.Match(input);
                if (matchIsArray.Success)
                {
                    var typename = matchIsArray.Groups["TYPE"].Value;
                    returntype = $"CArray<{GetCsTypeRecursive(typename, customenums)}>";
                }
                else
                {
                }
                return(returntype);
            }
            else
            {
                input = input.Trim(' ');
                if (AssemblyDictionary.EnumExists(input) || customenums.Contains(input))
                {
                    input = $"CEnum<{input}>";
                }
                return(REDReflection.GetWKitBaseTypeFromREDBaseType(input));
            }
        }
Пример #2
0
        private static CVariable GetRedProperty(IEditableVariable cvar, string propertyName)
        {
            foreach (var member in REDReflection.GetMembers(cvar))
            {
                try
                {
                    var redname = REDReflection.GetREDNameString(member);
                    if (redname != propertyName)
                    {
                        continue;
                    }

                    var prop  = cvar.accessor[cvar, member.Name];
                    var cprop = prop as CVariable;

                    return(cprop);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }

            return(null);
        }
        /// <summary>
        /// The instantiation step of the RedEngine-4 reflection.
        /// </summary>
        /// <param name="typename">Can be either a generic type such as CUint32 - then converted with GetWKitTypeFromREDType, or a complex type like a
        /// pointer to a class, a handle to an import file, an array, a soft reference, a static reference, various buffers, an enum.</param>
        /// <param name="varname">The variable name</param>
        /// <param name="cr2w">The cr2w base file</param>
        /// <param name="parentVariable">The class owning this attribute</param>
        /// <param name="readUnknownAsBytes"></param>
        /// <returns></returns>
        public static CVariable Create(string typename, string varname, CR2WFile cr2w, CVariable parentVariable, bool readUnknownAsBytes = true)
        {
            typename = REDReflection.GetWKitBaseTypeFromREDBaseType(typename);
            var fullname = typename;

            // check for normal type
            if (AssemblyDictionary.TypeExists(typename))
            {
                var type = AssemblyDictionary.GetTypeByName(typename);
                if (type != null)
                {
                    object instance = System.Activator.CreateInstance(type, cr2w, parentVariable, varname);
                    return(instance as CVariable);
                }
            }

            // check for enum types
            if (AssemblyDictionary.EnumExists(typename))
            {
                Enum e     = (Enum)System.Activator.CreateInstance(AssemblyDictionary.GetEnumByName(typename));
                var  cenum = MakeGenericEnumType(typeof(CEnum <>), e);
                return(cenum);
            }
            else if (CR2WManager.EnumExists(typename))
            {
                Enum e     = (Enum)System.Activator.CreateInstance(CR2WManager.GetEnumByName(typename));
                var  cenum = MakeGenericEnumType(typeof(CEnum <>), e);
                return(cenum);
            }
            // check for generic type
            else if (typename.StartsWith('['))
            {
                var idx = typename.IndexOf(']');

                string generictype = typename[(idx + 1)..];
Пример #4
0
        public static void WriteObject(IExportable instance, REDBinaryWriter red)
        {
            red.Write((byte)0);

            var fields = REDReflection.GetREDFields(instance.GetType());

            foreach (var field in fields)
            {
                var value = field.GetValue(instance);

                if (value == null || value == default)
                {
                    continue;
                }

                var(name, type) = REDReflection.GetREDNameTypePair(field);
                red.Write((CName)name);
                red.Write((CName)type);

                var start = red.BaseStream.Position;
                red.Write(0u);
                WriteProperty(value, red);

                var end = red.BaseStream.Position;
                red.BaseStream.Seek(start, SeekOrigin.Begin);
                red.Write(Convert.ToUInt32(end - start));
                red.BaseStream.Seek(end, SeekOrigin.Begin);
            }

            red.Write((ushort)0);
        }
Пример #5
0
        public void ParseObject(object instance, REDBinaryReader red)
        {
            // Each object is prefixed with a zero byte header.
            var b = red.ReadByte();

            if (b != 0)
            {
                throw new FormatException($"Invalid object null header: {b}");
            }

            // Keep looping until the 2 byte null termintator is reached.
            while (true)
            {
                var name = red.ReadCName();
                if (CName.IsNullOrEmpty(name))
                {
                    // 2 byte null terminator instead of the next name id indicates the end of the object.
                    break;
                }
                var type = red.ReadCName();

                var start = red.BaseStream.Position;
                var size  = red.ReadUInt32();
                // Size value includes the size of the uint size value itself (+ 4).
                if (size < sizeof(uint))
                {
                    throw new FormatException($"Invalid object size: {size}");
                }

                // Check to see if the current class contains a property with the name and type read.
                var field = REDReflection.GetREDField(instance.GetType(), name, type);
                if (field == null)
                {
                    throw new FormatException($"Property '{name}' : '{type}', not found in class {instance.GetType().Name}, Aborting!");
                }

                var value = ReadObject(field.FieldType, red);

                var diff = start.CompareTo(red.BaseStream.Position);
                if (diff != 0)
                {
                    throw new FormatException($"Property '{name}' : '{type}', read unknown size of bytes, aborting!");
                }

                field.SetValue(instance, value);
            }
        }
Пример #6
0
        private void InstantiateAllRedProps()
        {
            foreach (var item in this.GetREDMembers(true))
            {
                var o = accessor[this, item.Name];
                if (o is CVariable cvar)
                {
                }
                else // is null
                {
                    var att = item.GetMemberAttribute <REDAttribute>();
                    // instantiate
                    var vartype = REDReflection.GetREDTypeString(item.Type, att.Flags);
                    var varname = REDReflection.GetREDNameString(item);

                    var newvar = CR2WTypeManager.Create(vartype, varname, this.cr2w, this);     // create new variable and parent to this
                    if (newvar != null)
                    {
                        accessor[this, item.Name] = newvar;
                    }
                }
            }
        }
 public CArrayCompressed(CR2WFile cr2w, CVariable parent, string name) : base(cr2w, parent, name)
 {
     Elementtype = REDReflection.GetREDTypeString(typeof(T));
 }
Пример #8
0
        /// <summary>
        /// The instantiation step of the RedEngine-3 reflection.
        /// </summary>
        /// <param name="typename">Can be either a generic type such as CUint32 - then converted with GetWKitTypeFromREDType, or a complex type like a
        /// pointer to a class, a handle to an import file, an array, a soft reference, a static reference, various buffers, an enum.</param>
        /// <param name="varname">The variable name</param>
        /// <param name="cr2w">The cr2w base file</param>
        /// <param name="parentVariable">The class owning this attribute</param>
        /// <param name="readUnknownAsBytes"></param>
        /// <returns></returns>
        public static CVariable Create(string typename, string varname, CR2WFile cr2w, CVariable parentVariable, bool readUnknownAsBytes = true)
        {
            typename = REDReflection.GetWKitBaseTypeFromREDBaseType(typename);
            var fullname = typename;

            // check for normal type
            if (AssemblyDictionary.TypeExists(typename))
            {
                var type = AssemblyDictionary.GetTypeByName(typename);
                if (type != null)
                {
                    object instance = System.Activator.CreateInstance(type, cr2w, parentVariable, varname);
                    return(instance as CVariable);
                }
            }

            // check for enum types
            if (AssemblyDictionary.EnumExists(typename))
            {
                Enum e     = (Enum)System.Activator.CreateInstance(AssemblyDictionary.GetEnumByName(typename));
                var  cenum = MakeGenericEnumType(typeof(CEnum <>), e);
                return(cenum);
            }
            else if (CR2WManager.EnumExists(typename))
            {
                Enum e     = (Enum)System.Activator.CreateInstance(CR2WManager.GetEnumByName(typename));
                var  cenum = MakeGenericEnumType(typeof(CEnum <>), e);
                return(cenum);
            }
            // check for generic type
            else if (typename.StartsWith('['))
            {
                string    generictype = typename.Substring(3);
                CVariable innerobject = Create(generictype, "", cr2w, null);
                var       arrayacc    = MakeArray(typeof(CArrayFixedSize <>), innerobject.GetType());
                //arrayacc.Flags = new List<int>() { int.Parse(matchArrayType.Groups[1].Value) };
                arrayacc.Elementtype = generictype;
                return(arrayacc as CVariable);
            }
            else if (typename.Contains(':'))
            {
                #region GENERIC TYPES
                string[] splits      = typename.Split(':');
                string   generictype = splits.First();
                string   innertype   = string.Join(":", splits.Skip(1));
                // e.g. handle:CEntityTemplate
                switch (generictype)
                {
                case "CHandle":
                case "handle":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CHandle <>), innerobject));
                }

                case "wCHandle":
                case "whandle":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(wCHandle <>), innerobject));
                }

                case "CrRef":
                case "rRef":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(rRef <>), innerobject));
                }

                case "CraRef":
                case "raRef":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(raRef <>), innerobject));
                }

                case "array":
                {
                    // match pattern e.g.
                    // array:            (array:)Float
                    // array of array:   (array:)handle:meshMeshAppearance


                    CVariable      innerobject = Create(innertype, "", cr2w, null);
                    IArrayAccessor arrayacc    = MakeArray(typeof(CArray <>), innerobject.GetType());
                    arrayacc.Elementtype = innertype;
                    return(arrayacc as CVariable);
                }

                case "static":
                {
                    typename = generictype;

                    // match pattern e.g.
                    // static:  (4),(Uint32)
                    var regArrayType   = new Regex(@"(\d+),(.+)");
                    var matchArrayType = regArrayType.Match(fullname);
                    if (matchArrayType.Success)
                    {
                        CVariable innerobject = Create(matchArrayType.Groups[2].Value, "", cr2w, null);
                        var       arrayacc    = MakeArray(typeof(CStatic <>), innerobject.GetType());
                        //arrayacc.Flags = new List<int>() { int.Parse(matchArrayType.Groups[1].Value) };
                        arrayacc.Elementtype = matchArrayType.Groups[2].Value;
                        return(arrayacc as CVariable);
                    }
                    else
                    {
                        throw new InvalidParsingException($"Invalid static type format: typename: {typename}.");
                    }
                }

                case "CEnum":
                {
                    Enum innerobject = CreateEnum(innertype);
                    return(MakeGenericEnumType(typeof(CEnum <>), innerobject));
                }

                default:
                {
                    throw new MissingTypeException(generictype);
                }
                }
                #endregion
            }
            else
            {
                // check if custom type
                if (CR2WManager.TypeExists(typename))
                {
                    var    type     = CR2WManager.GetTypeByName(typename);
                    object instance = System.Activator.CreateInstance(type, cr2w, parentVariable, varname);
                    return(instance as CVariable);
                }


                // this should never happen

                if (!cr2w.UnknownTypes.Contains(fullname))
                {
                    cr2w.UnknownTypes.Add(fullname);
                }

                if (readUnknownAsBytes)
                {
                    return(new CBytes(cr2w, parentVariable, $"UNKNOWN:{typename}:{varname}"));
                }
                else
                {
                    return(null);
                }
            }


            #region LOCAL FUNCTIONS


            IArrayAccessor MakeArray(Type arraytype, Type generictype)
            {
                Type elementType;

                if (arraytype == typeof(CStatic <>))
                {
                    elementType = typeof(CStatic <>).MakeGenericType(generictype);
                }
                else if (arraytype == typeof(CArrayFixedSize <>))
                {
                    elementType = typeof(CArrayFixedSize <>).MakeGenericType(generictype);
                }
                else if (arraytype == typeof(CArray <>))
                {
                    elementType = typeof(CArray <>).MakeGenericType(generictype);
                }
                else
                {
                    throw new NotImplementedException();
                }


                var array = System.Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;

                return(array as IArrayAccessor);
            }

            CVariable MakeGenericType(Type gentype, CVariable innerobject)
            {
                if (innerobject != null)
                {
                    Type      elementType = gentype.MakeGenericType(innerobject.GetType());
                    CVariable handle      = System.Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;
                    return(handle);
                }
                else
                {
                    throw new Exception();
                }
            }

            CVariable MakeGenericEnumType(Type gentype, Enum innerobject)
            {
                if (innerobject != null)
                {
                    Type      elementType = gentype.MakeGenericType(innerobject.GetType());
                    CVariable handle      = System.Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;
                    return(handle);
                }
                else
                {
                    throw new Exception();
                }
            }

            #endregion
        }
Пример #9
0
        /// <summary>
        /// The instantiation step of the RedEngine-3 reflection.
        /// </summary>
        /// <param name="typename">Can be either a generic type such as CUint32 - then converted with GetWKitTypeFromREDType, or a complex type like a
        /// pointer to a class, a handle to an import file, an array, a soft reference, a static reference, various buffers, an enum.</param>
        /// <param name="varname">The variable name</param>
        /// <param name="cr2w">The cr2w base file</param>
        /// <param name="parentVariable">The class owning this attribute</param>
        /// <param name="readUnknownAsBytes"></param>
        /// <returns></returns>
        public static CVariable Create(string typename, string varname, CR2WFile cr2w, CVariable parentVariable, bool readUnknownAsBytes = true)
        {
            typename = REDReflection.GetWKitBaseTypeFromREDBaseType(typename);
            var fullname = typename;

            // check for normal type
            if (AssemblyDictionary.TypeExists(typename))
            {
                var type = AssemblyDictionary.GetTypeByName(typename);
                if (type != null)
                {
                    object instance = Activator.CreateInstance(type, cr2w, parentVariable, varname);
                    return(instance as CVariable);
                }
            }

            // check for enum types
            if (AssemblyDictionary.EnumExists(typename))
            {
                Enum e     = (Enum)Activator.CreateInstance(AssemblyDictionary.GetEnumByName(typename));
                var  cenum = MakeGenericEnumType(typeof(CEnum <>), e);
                return(cenum);
            }
            else if (CR2WManager.EnumExists(typename))
            {
                Enum e     = (Enum)Activator.CreateInstance(CR2WManager.GetEnumByName(typename));
                var  cenum = MakeGenericEnumType(typeof(CEnum <>), e);
                return(cenum);
            }
            // check for generic type
            else if (typename.Contains(':'))
            {
                #region GENERIC TYPES
                string[] splits      = typename.Split(':');
                string   generictype = splits.First();
                string   innertype   = string.Join(":", splits.Skip(1));
                // e.g. handle:CEntityTemplate
                switch (generictype)
                {
                case "CHandle":
                case "handle":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CHandle <>), innerobject));
                }

                case "CPtr":
                case "ptr":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CPtr <>), innerobject));
                }

                case "CSoft":
                case "soft":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CSoft <>), innerobject));
                }

                case "array":
                {
                    // match pattern e.g.
                    // array:            Array: (2),(0),(handle:CBitmapTexture)
                    // array:            Array: (2),(0),(Int32)
                    // array of array:   Array: (2),(0),(Array:133,0,EngineQsTransform)

                    string[] arraysplits = innertype.Split(',');
                    string   flag1       = arraysplits[0];
                    string   flag2       = arraysplits[1];
                    string   body        = string.Join(",", arraysplits.Skip(2));
                    if (arraysplits.Length >= 3)
                    {
                        //byte arrays, these can be huge, using ordinary arrays is just too slow.
                        if (body == "Uint8" || body == "Int8")
                        {
                            var bytearray = new CByteArray(cr2w, parentVariable, varname);
                            // save the actual redengine type for serialization: e.g. array:2,0,Uint8
                            bytearray.InternalType = typename;
                            return(bytearray);
                        }

                        // all other arrays
                        CVariable      innerobject = Create(body, "", cr2w, null);
                        IArrayAccessor arrayacc    = MakeArray(typeof(CArray <>), innerobject.GetType());
                        arrayacc.Flags = new List <int>()
                        {
                            int.Parse(flag1), int.Parse(flag2)
                        };
                        if (innerobject is IArrayAccessor accessor && accessor.Flags != null)
                        {
                            arrayacc.Flags.AddRange(accessor.Flags);
                        }
                        arrayacc.Elementtype = body;
                        return(arrayacc as CVariable);
                    }
                    else
                    {
                        CVariable      innerobject = Create(innertype, "", cr2w, null);
                        IArrayAccessor arrayacc    = MakeArray(typeof(CArray <>), innerobject.GetType());
                        arrayacc.Elementtype = body;
                        return(arrayacc as CVariable);
                    }
                }

                case "static":
                {
                    typename = generictype;

                    // match pattern e.g.
                    // static:  (4),(Uint32)
                    var regArrayType   = new Regex(@"(\d+),(.+)");
                    var matchArrayType = regArrayType.Match(fullname);
                    if (matchArrayType.Success)
                    {
                        CVariable innerobject = Create(matchArrayType.Groups[2].Value, "", cr2w, null);
                        var       arrayacc    = MakeArray(typeof(CStatic <>), innerobject.GetType());
                        arrayacc.Flags = new List <int>()
                        {
                            int.Parse(matchArrayType.Groups[1].Value)
                        };
                        arrayacc.Elementtype = matchArrayType.Groups[2].Value;
                        return(arrayacc as CVariable);
                    }
                    else
                    {
                        throw new InvalidParsingException($"Invalid static type format: typename: {typename}.");
                    }
                }

                case "CBufferUInt16":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CBufferUInt16 <>), innerobject));
                }

                case "CBufferUInt32":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CBufferUInt32 <>), innerobject));
                }

                case "CBufferVLQInt32":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CBufferVLQInt32 <>), innerobject));
                }

                case "CCompressedBuffer":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CCompressedBuffer <>), innerobject));
                }

                case "CPaddedBuffer":
                {
                    CVariable innerobject = Create(innertype, "", cr2w, null);
                    return(MakeGenericType(typeof(CPaddedBuffer <>), innerobject));
                }

                case "CEnum":
                {
                    Enum innerobject = CreateEnum(innertype);
                    return(MakeGenericEnumType(typeof(CEnum <>), innerobject));
                }

                default:
                {
                    throw new NotImplementedException();
                }
                }
                #endregion
            }
            else
            {
                #region FIXED SIZE ARRAYS
                // match pattern e.g.
                // [(1)](Bezier2dHandle)
                var regFixedSizeArray   = new Regex(@"^\[(\d+)\](.+)$");
                var matchFixedSizeArray = regFixedSizeArray.Match(typename);
                if (matchFixedSizeArray.Success)
                {
                    CVariable innerobject = Create(matchFixedSizeArray.Groups[2].Value, "", cr2w, null);
                    var       arrayacc    = MakeArray(typeof(CArrayFixedSize <>), innerobject.GetType());
                    arrayacc.Flags = new List <int>()
                    {
                        int.Parse(matchFixedSizeArray.Groups[1].Value)
                    };
                    arrayacc.Elementtype = matchFixedSizeArray.Groups[2].Value;
                    return(arrayacc as CVariable);
                }
                #endregion

                if (fullname.Contains("@SItem"))
                {
                    cr2w.UnknownTypes.Add($"Congratulations! You have found one of the hidden e3 files! These files are special." +
                                          $" If you edited this file and are experiencing errors, please contact a member of the Wkit Team. ErrorCode: {fullname}");
                    return(new SItem(cr2w, parentVariable, varname));
                }
                else if (fullname.Contains("#CEnvironmentDefinition"))
                {
                    cr2w.UnknownTypes.Add($"Congratulations! You have found one of the hidden e3 files! These files are special." +
                                          $" If you edited this file and are experiencing errors, please contact a member of the Wkit Team. ErrorCode: {fullname}");
                    return(new CHandle <CEnvironmentDefinition>(cr2w, parentVariable, varname));
                }
                else
                {
                    // check if custom type
                    if (CR2WManager.TypeExists(typename))
                    {
                        var    type     = CR2WManager.GetTypeByName(typename);
                        object instance = Activator.CreateInstance(type, cr2w, parentVariable, varname);
                        return(instance as CVariable);
                    }


                    // this should never happen

                    if (!cr2w.UnknownTypes.Contains(fullname))
                    {
                        cr2w.UnknownTypes.Add(fullname);
                    }

                    if (readUnknownAsBytes)
                    {
                        return(new CBytes(cr2w, parentVariable, $"UNKNOWN:{typename}:{varname}"));
                    }
                    else
                    {
                        return(null);
                    }
                }
            }


            #region LOCAL FUNCTIONS


            IArrayAccessor MakeArray(Type arraytype, Type generictype)
            {
                Type elementType;

                if (arraytype == typeof(CStatic <>))
                {
                    elementType = typeof(CStatic <>).MakeGenericType(generictype);
                }
                else if (arraytype == typeof(CArrayFixedSize <>))
                {
                    elementType = typeof(CArrayFixedSize <>).MakeGenericType(generictype);
                }
                else if (arraytype == typeof(CArray <>))
                {
                    elementType = typeof(CArray <>).MakeGenericType(generictype);
                }
                else
                {
                    throw new NotImplementedException();
                }


                var array = Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;

                return(array as IArrayAccessor);
            }

            CVariable MakeGenericType(Type gentype, CVariable innerobject)
            {
                if (innerobject != null)
                {
                    Type      elementType = gentype.MakeGenericType(innerobject.GetType());
                    CVariable handle      = Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;
                    return(handle);
                }
                else
                {
                    throw new Exception();
                }
            }

            CVariable MakeGenericEnumType(Type gentype, Enum innerobject)
            {
                if (innerobject != null)
                {
                    Type      elementType = gentype.MakeGenericType(innerobject.GetType());
                    CVariable handle      = Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;
                    return(handle);
                }
                else
                {
                    throw new Exception();
                }
            }

            #endregion
        }
Пример #10
0
            public string ToVarString()
            {
                var wktype = REDReflection.GetWKitBaseTypeFromREDBaseType(Type);

                return($"[RED(\"{Name}\")] public {wktype} {Name.FirstCharToUpper()} {{ get; set; }}");
            }
Пример #11
0
        public static (List <string>, List <SImportEntry>) GenerateStringtableInner(CR2WFile file)
        {
            var dbg_trace    = new List <string>();
            var newnameslist = new Dictionary <string, string> {
                { "", "" }
            };
            var newimportslist = new List <SImportEntry>();
            var newsoftlist    = new List <SImportEntry>();
            var idlist         = new HashSet <string>();

            foreach (var c in file.Chunks)
            {
                LoopWrapper(new SNameArg(EStringTableMod.SkipName, c.Data));
            }

            newimportslist.AddRange(newsoftlist);

            return(newnameslist.Values.ToList(), newimportslist);

            void LoopWrapper(SNameArg var)
            {
                if (idlist.Contains(var.Var.UniqueIdentifier))
                {
                    return;
                }

                //collection.Add(var);
                dbg_trace.Add($"{var.Var.UniqueIdentifier} - {var.Mod}");
                AddStrings(var);

                List <SNameArg> nextl = GetVariables(var.Var);

                if (nextl == null)
                {
                    return;
                }
                foreach (var l in nextl.Where(l => l.Var != null))
                {
                    LoopWrapper(l);
                }
            }

            List <SNameArg> GetVariables(IEditableVariable ivar)
            {
                //check for looping references
                if (idlist.Contains(ivar.UniqueIdentifier))
                {
                    return(null);
                }
                else
                {
                    idlist.Add(ivar.UniqueIdentifier);
                }

                var returnedVariables = new List <SNameArg>();

                // if variable is generic type or some special case
                switch (ivar)
                {
                case IREDArray a:
                    switch (a)
                    {
                    case CArray <CName> cacn:
                        returnedVariables.Add(new SNameArg(EStringTableMod.None, a));         //???
                        break;

                    case CArray <CBool> cacb:
                    case CArray <CUInt16> cacu16:
                    case CArray <CInt16> caci16:
                    case CArray <CUInt32> cacu32:
                    case CArray <CInt32> caci32:
                    case CArray <CUInt64> cacu64:
                    case CArray <CInt64> caci64:
                        break;

                    default:
                        var elements = a.GetEditableVariables();
                        foreach (var item in elements)
                        {
                            returnedVariables.Add(new SNameArg(EStringTableMod.SkipNameAndType, item));
                        }
                        break;
                    }
                    break;

                case IREDPtr h:
                    if (h.GetReference() != null)
                    {
                        returnedVariables.Add(new SNameArg(EStringTableMod.None, h.GetReference().Data));
                    }
                    break;

                case IREDRef s:
                    break;

                case IREDBufferVariant ivariant:
                    var mod = EStringTableMod.None;
                    returnedVariables.Add(new SNameArg(mod, ivariant.Variant));
                    break;

                case CVariant cVariant:
                    returnedVariables.Add(new SNameArg(EStringTableMod.SkipName, cVariant.Variant));
                    break;

                // check all other CVariables
                case CVariable cvar:
                {
                    // skip some custom buffers
                    if (cvar is gameCookedDeviceDataCompressed)
                    {
                        return(null);
                    }


                    // add parent if not already in guidlist
                    // don't add array type parents, don't add IREDBufferVariant type parents
                    if (cvar.ParentVar != null &&
                        !cvar.ParentVar.GetType().IsGenericType &&
                        !(cvar.ParentVar is IREDBufferVariant) &&
                        !idlist.Contains(cvar.ParentVar.UniqueIdentifier))
                    {
                        returnedVariables.Add(new SNameArg(EStringTableMod.None, cvar.ParentVar));
                    }

                    returnedVariables.AddRange(cvar.UnknownCVariables.Select(_ => new SNameArg(EStringTableMod.None, _)));
                    foreach (var item in cvar.GetREDMembers(true))
                    {
                        var o = cvar.accessor[cvar, item.Name];
                        if (o is CVariable cvar2)
                        {
                            if (cvar2.IsSerialized)
                            {
                                if (REDReflection.GetREDAttribute(item) is REDBufferAttribute)
                                {
                                    returnedVariables.Add(new SNameArg(EStringTableMod.SkipNameAndType, cvar2));
                                }
                                else
                                {
                                    returnedVariables.Add(new SNameArg(EStringTableMod.None, cvar2));
                                }
                            }
                        }
                    }

                    // custom serialization
                    if (cvar is gameDeviceResourceData gdrd)
                    {
                        returnedVariables.AddRange(gdrd.CookedDeviceData
                                                   .Select(_ => _.ClassName)
                                                   .Select(_ => new SNameArg(EStringTableMod.SkipNameAndType, _)));
                    }

                    if (cvar is scnAnimName scnname && scnname.Unk1 != null)
                    {
                        returnedVariables.AddRange(scnname.Unk1
                                                   .Select(_ => new SNameArg(EStringTableMod.SkipNameAndType, _)));
                    }


                    break;
                }

                default:
                    break;
                }

                return(returnedVariables);
            }

            void AddStrings(SNameArg tvar)
            {
                var var = tvar.Var;

                // skip some custom buffers
                if (var is gameCookedDeviceDataCompressed)
                {
                    return;
                }

                CheckVarNameAndTypes();

                switch (var)
                {
                case IREDHandle handle:
                {
                    if (!handle.ChunkHandle)
                    {
                        AddUniqueToTable(handle.ClassName);
                        var flags = EImportFlags.Default;

                        if ((var.Cr2wFile as CR2WFile).Embedded.Any(_ => _.ImportPath == handle.DepotPath))
                        {
                            flags = EImportFlags.Inplace;
                        }

                        var importtuple = new SImportEntry(handle.ClassName, handle.DepotPath, flags);
                        if (!newimportslist.Contains(importtuple))
                        {
                            newimportslist.Add(importtuple);
                        }
                    }

                    break;
                }

                case IREDRef soft:
                {
                    if (/*!(string.IsNullOrEmpty(s.ClassName) &&*/ !string.IsNullOrEmpty(soft.DepotPath))
                    {
                        //FIXME: calculate this properly
                        //var flags = EImportFlags.Default;
                        //if (s.REDType.StartsWith("raRef:"))
                        //    flags = EImportFlags.Soft;

                        var flags = soft.Flags;

                        var stuple = new SImportEntry("", soft.DepotPath, flags);
                        if (newsoftlist.All(_ => _.Path != soft.DepotPath))
                        {
                            newsoftlist.Add(stuple);
                        }
                    }

                    break;
                }

                case CName n:
                    AddUniqueToTable(n.Value);
                    break;

                case IREDArray when var is IREDBuffer buffer:
                {
                    foreach (var ivar in buffer.GetEditableVariables())
                    {
                        if (ivar is not IREDHandle ha)
                        {
                            continue;
                        }
                        if (ha.ChunkHandle)
                        {
                            continue;
                        }

                        AddUniqueToTable(ha.ClassName);
                        var flags = EImportFlags.Default;
                        if (ha.REDName == "template")
                        {
                            flags = EImportFlags.Template;
                        }
                        var importtuple = new SImportEntry(ha.ClassName, ha.DepotPath, flags);
                        if (!newimportslist.Contains(importtuple))
                        {
                            newimportslist.Add(importtuple);
                        }
                    }

                    break;
                }

                case IREDArray:
                {
                    CheckVarNameAndTypes();

                    if (var is CArray <CName> aa)
                    {
                        foreach (var element in aa)
                        {
                            AddUniqueToTable(element.Value);
                        }
                    }

                    break;
                }

                case IREDEnum {
                        IsFlag: true
                } enumAccessor:
                    {
                        foreach (var enumstring in enumAccessor.EnumValueList)
                        {
                            AddUniqueToTable(enumstring);
                        }
                        break;
                    }

                case IREDEnum enumAccessor:
                    AddUniqueToTable(enumAccessor.GetAttributeVal());
                    break;
                }


                void CheckVarNameAndTypes()
                {
                    switch (tvar.Mod)
                    {
                    case EStringTableMod.SkipType:
                        AddUniqueToTable(var.REDName);
                        break;

                    case EStringTableMod.SkipName:
                        AddUniqueToTable(var.REDType);
                        break;

                    case EStringTableMod.SkipNameAndType:
                        break;

                    case EStringTableMod.TypeFirst:
                        AddUniqueToTable(var.REDType);
                        AddUniqueToTable(var.REDName);
                        break;

                    case EStringTableMod.None:
                    default:
                        AddUniqueToTable(var.REDName);
                        AddUniqueToTable(var.REDType);
                        break;
                    }
                }
            }

            void AddUniqueToTable(string str)
            {
                if (string.IsNullOrEmpty(str))
                {
                    // todo
                }
                else
                {
                    if (!newnameslist.ContainsKey(str))
                    {
                        // hack for CApexClothResource *sigh*
                        if (str == "apexMaterialNames")
                        {
                            if (!newnameslist.ContainsKey("apexBinaryAsset"))
                            {
                                newnameslist.Add("apexBinaryAsset", "apexBinaryAsset");
                            }
                            if (!newnameslist.ContainsKey("array: 95, 0, Uint8"))
                            {
                                newnameslist.Add("array:95,0,Uint8", "array:95,0,Uint8");
                            }
                        }

                        newnameslist.Add(str, str);
                    }
                }
            }
        }
Пример #12
0
        /// <summary>
        /// The instantiation step of the RedEngine-3 reflection.
        /// </summary>
        /// <param name="typename">Can be either a generic type such as CUint32 - then converted with GetWKitTypeFromREDType, or a complex type like a
        /// pointer to a class, a handle to an import file, an array, a soft reference, a static reference, various buffers, an enum.</param>
        /// <param name="varname">The variable name</param>
        /// <param name="cr2w">The cr2w base file</param>
        /// <param name="parentVariable">The class owning this attribute</param>
        /// <param name="readUnknownAsBytes"></param>
        /// <returns></returns>
        public static CVariable Create(string typename, string varname, CR2WFile cr2w, CVariable parentVariable, bool readUnknownAsBytes = true)
        {
            typename = REDReflection.GetWKitBaseTypeFromREDBaseType(typename);

            // first try to create instance of type
            #region W3 TYPES
            try
            {
                var type = Type.GetType($"WolvenKit.CR2W.Types.{typename}", false, false);
                // if succesful return as CVariable
                if (type != null)
                {
                    //var instance = type.GetMethod("Create").Invoke(type, new object[]{ cr2w, parentVariable, varname });

                    object instance = Activator.CreateInstance(type, cr2w, parentVariable, varname);
                    return(instance as CVariable);
                }
            }
            catch (System.IO.FileLoadException)
            {
            }
            #endregion

            var fullname = typename;
            // check for enum
            if (typeof(Enums).GetNestedTypes().Select(_ => _.Name).Contains(typename))
            {
                Enum e = (Enum)Activator.CreateInstance(typeof(Enums).GetNestedTypes().FirstOrDefault(_ => _.Name == typename));

                //if (e.GetType().IsDefined(typeof(FlagsAttribute), false))
                //{
                //    typename = REDReflection.GetWKitTypeFromREDType(typename);
                //    var etype = Type.GetType($"WolvenKit.CR2W.Types.{typename}");
                //    object einstance = Activator.CreateInstance(etype, cr2w, parentVariable, varname);
                //    return einstance as CVariable;
                //}

                var cenum = MakeGenericEnumType(typeof(CEnum <>), e);
                return(cenum);
            }
            // finally, check for generic type
            else if (typename.Contains(':'))
            {
                //try
                //{
                #region GENERIC TYPES
                // match pattern e.g.
                // (handle):(CGenericGrassMask) or
                // (array):(2,0,handle:CBitmapTexture)
                var reg   = new Regex(@"^(\w+):(.+)$");
                var match = reg.Match(typename);
                if (match.Success)
                {
                    switch (match.Groups[1].Value)
                    {
                    case "CHandle":
                    case "handle":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CHandle <>), innerobject));
                    }

                    case "CPtr":
                    case "ptr":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CPtr <>), innerobject));
                    }

                    case "CSoft":
                    case "soft":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CSoft <>), innerobject));
                    }

                    case "array":
                    {
                        typename = match.Groups[1].Value;

                        // match pattern e.g.
                        // array:            Array: (2),(0),(handle:CBitmapTexture)
                        // array:            Array: (2),(0),(Int32)
                        // array of array:   Array: (2),(0),(Array:133,0,EngineQsTransform)
                        var regArrayType   = new Regex(@"(\d+),(\d+),(.+)");
                        var matchArrayType = regArrayType.Match(fullname);
                        if (matchArrayType.Success)
                        {
                            //byte arrays, these can be huge, using ordinary arrays is just too slow.
                            if (matchArrayType.Groups[3].Value == "Uint8" || matchArrayType.Groups[3].Value == "Int8")
                            {
                                var bytearray = new CByteArray(cr2w, parentVariable, varname);
                                bytearray.InternalType = fullname;
                                return(bytearray);
                            }



                            CVariable      innerobject = Create(matchArrayType.Groups[3].Value, "", cr2w, null);
                            IArrayAccessor arrayacc    = MakeArray(typeof(CArray <>), innerobject.GetType());
                            arrayacc.Flags = new List <int>()
                            {
                                int.Parse(matchArrayType.Groups[1].Value), int.Parse(matchArrayType.Groups[2].Value)
                            };
                            if (innerobject is IArrayAccessor accessor && accessor.Flags != null)
                            {
                                arrayacc.Flags.AddRange(accessor.Flags);
                            }


                            arrayacc.Elementtype = matchArrayType.Groups[3].Value;

                            return(arrayacc as CVariable);
                        }
                        // for CArrays of other types
                        else
                        {
                            //throw new InvalidParsingException($"Invalid array type format: typename: {typename}.");
                            CVariable      innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                            IArrayAccessor arrayacc    = MakeArray(typeof(CArray <>), innerobject.GetType());
                            arrayacc.Elementtype = matchArrayType.Groups[3].Value;
                            return(arrayacc as CVariable);
                        }
                    }

                    case "static":
                    {
                        typename = match.Groups[1].Value;

                        // match pattern e.g.
                        // static:  (4),(Uint32)
                        var regArrayType   = new Regex(@"(\d+),(.+)");
                        var matchArrayType = regArrayType.Match(fullname);
                        if (matchArrayType.Success)
                        {
                            CVariable innerobject = Create(matchArrayType.Groups[2].Value, "", cr2w, null);
                            var       arrayacc    = MakeArray(typeof(CStatic <>), innerobject.GetType());
                            arrayacc.Flags = new List <int>()
                            {
                                int.Parse(matchArrayType.Groups[1].Value)
                            };
                            arrayacc.Elementtype = matchArrayType.Groups[2].Value;
                            return(arrayacc as CVariable);
                        }
                        else
                        {
                            throw new InvalidParsingException($"Invalid static type format: typename: {typename}.");
                        }
                    }

                    case "CBufferUInt16":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CBufferUInt16 <>), innerobject));
                    }

                    case "CBufferUInt32":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CBufferUInt32 <>), innerobject));
                    }

                    case "CBufferVLQInt32":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CBufferVLQInt32 <>), innerobject));
                    }

                    case "CCompressedBuffer":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CCompressedBuffer <>), innerobject));
                    }

                    case "CPaddedBuffer":
                    {
                        CVariable innerobject = Create(match.Groups[2].Value, "", cr2w, null);
                        return(MakeGenericType(typeof(CPaddedBuffer <>), innerobject));
                    }

                    case "CEnum":
                    {
                        Enum innerobject = CreateEnum(match.Groups[2].Value);
                        return(MakeGenericEnumType(typeof(CEnum <>), innerobject));
                    }

                    default:
                    {
                        typename = match.Groups[1].Value;

                        throw new NotImplementedException();

                        break;
                    }
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }
                #endregion
                //}
                //catch (Exception ex)
                //{
                //    throw ex;
                //}
            }
            else
            {
                #region FIXED SIZE ARRAYS
                // match pattern e.g.
                // [(1)](Bezier2dHandle)
                var regFixedSizeArray   = new Regex(@"^\[(\d+)\](.+)$");
                var matchFixedSizeArray = regFixedSizeArray.Match(typename);
                if (matchFixedSizeArray.Success)
                {
                    CVariable innerobject = Create(matchFixedSizeArray.Groups[2].Value, "", cr2w, null);
                    var       arrayacc    = MakeArray(typeof(CArrayFixedSize <>), innerobject.GetType());
                    arrayacc.Flags = new List <int>()
                    {
                        int.Parse(matchFixedSizeArray.Groups[1].Value)
                    };
                    arrayacc.Elementtype = matchFixedSizeArray.Groups[2].Value;
                    return(arrayacc as CVariable);
                }
                #endregion

                if (fullname.Contains("@SItem"))
                {
                    cr2w.UnknownTypes.Add($"Congratulations! You have found one of the hidden e3 files! These files are special." +
                                          $" If you edited this file and are experiencing errors, please contact a member of the Wkit Team. ErrorCode: {fullname}");
                    return(new SItem(cr2w, parentVariable, varname));
                }
                else if (fullname.Contains("#CEnvironmentDefinition"))
                {
                    cr2w.UnknownTypes.Add($"Congratulations! You have found one of the hidden e3 files! These files are special." +
                                          $" If you edited this file and are experiencing errors, please contact a member of the Wkit Team. ErrorCode: {fullname}");
                    return(new CHandle <CEnvironmentDefinition>(cr2w, parentVariable, varname));
                }
                else
                {
                    if (!cr2w.UnknownTypes.Contains(fullname))
                    {
                        cr2w.UnknownTypes.Add(fullname);
                    }

                    // this should never happen

                    if (readUnknownAsBytes)
                    {
                        return(new CBytes(cr2w, parentVariable, "unknownBytes"));
                    }
                    else
                    {
                        return(null);
                    }
                }
            }


            #region LOCAL FUNCTIONS


            IArrayAccessor MakeArray(Type arraytype, Type generictype)
            {
                Type elementType = typeof(CArray <>);

                if (arraytype == typeof(CStatic <>))
                {
                    elementType = typeof(CStatic <>).MakeGenericType(generictype);
                }
                else if (arraytype == typeof(CArrayFixedSize <>))
                {
                    elementType = typeof(CArrayFixedSize <>).MakeGenericType(generictype);
                }
                else if (arraytype == typeof(CArray <>))
                {
                    elementType = typeof(CArray <>).MakeGenericType(generictype);
                }
                else
                {
                    throw new NotImplementedException();
                }


                var array = Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;

                return(array as IArrayAccessor);
            }

            CVariable MakeGenericType(Type gentype, CVariable innerobject)
            {
                if (innerobject != null)
                {
                    Type      elementType = gentype.MakeGenericType(innerobject.GetType());
                    CVariable handle      = Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;
                    return(handle);
                }
                else
                {
                    throw new Exception();
                }
            }

            CVariable MakeGenericEnumType(Type gentype, Enum innerobject)
            {
                if (innerobject != null)
                {
                    Type      elementType = gentype.MakeGenericType(innerobject.GetType());
                    CVariable handle      = Activator.CreateInstance(elementType, cr2w, parentVariable, varname) as CVariable;
                    return(handle);
                }
                else
                {
                    throw new Exception();
                }
            }

            #endregion
        }