Exemple #1
0
        /// <summary>
        /// Gets all available types, custom and vanilla for a given typename
        /// </summary>
        /// <param name="typename"></param>
        /// <returns></returns>
        public static IEnumerable <Type> GetAvailableTypes(string typename)
        {
            var availableTypes = new List <Type>();

            if (AssemblyDictionary.TypeExists(typename))
            {
                availableTypes.Add(AssemblyDictionary.GetTypeByName(typename));
                var subclasses = AssemblyDictionary.GetSubClassesOf(AssemblyDictionary.GetTypeByName(typename));
                availableTypes.AddRange(subclasses);

                // check if subclasses exist in custom assemblies
                var ssubclasses = CR2WManager.GetSubClassesOf(AssemblyDictionary.GetTypeByName(typename));
                availableTypes.AddRange(ssubclasses);
            }
            else if (CR2WManager.TypeExists(typename))
            {
                availableTypes.Add(CR2WManager.GetTypeByName(typename));
                var subclasses = CR2WManager.GetSubClassesOf(CR2WManager.GetTypeByName(typename));
                availableTypes.AddRange(subclasses);

                // check if subclasses exist in main assembly
                var ssubclasses = AssemblyDictionary.GetSubClassesOf(CR2WManager.GetTypeByName(typename));
                availableTypes.AddRange(ssubclasses);
            }
            else
            {
                //MainController.LogString(
                //    "No such type exists. Make sure you have all custom types in a .ws file inside the modproject.",
                //    Logtype.Error);
                return(null);
            }

            return(availableTypes.Distinct());
        }
Exemple #2
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));
            }
        }
        /// <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)..];
Exemple #4
0
        public IEnumerable <ICR2WExport> GetReferenceChunks()
        {
            var refType = AssemblyDictionary.GetTypeByName(ReferenceType);
            var types   = AssemblyDictionary.GetSubClassesOf(refType)
                          .Select(_ => _.Name).ToList();

            return(Cr2wFile.Chunks.Where(cr2WExport => types.Contains(cr2WExport.REDType)).ToList());
        }
Exemple #5
0
        private static void ProcessConfigFile(string FileName)
        {
            var    FName    = Path.GetFileName(FileName);
            var    Ext      = Path.GetExtension(FileName);
            var    BaseName = FName.Replace(Ext, " ").Trim();
            string Text     = File.ReadAllText(FileName);

            if (Ext.ToLower().Equals(EXT))
            {
                string[] Tokens     = BaseName.Split(PropSeparators);
                string   AssembName = "";
                string   PropName   = "Global";
                string   ClassName  = BaseName;

                if (Tokens.Length == 1)
                {
                    AssembName = BaseName.Split('.')[0];
                }

                else if (Tokens.Length == 2)
                {
                    if (Tokens[0].Contains("."))
                    {
                        ClassName  = Tokens[0];
                        AssembName = BaseName.Split('.')[0];
                        PropName   = Tokens[1];
                    }
                    else
                    {
                        AssembName = Tokens[0];
                        ClassName  = Tokens[1];
                    }
                }

                else if (Tokens.Length >= 3)
                {
                    AssembName = Tokens[0];
                    ClassName  = Tokens[1];
                    PropName   = Tokens[2];
                }

                if (AssemblyDictionary.ContainsKey(AssembName) && !Processed.Contains(AssembName))
                {
                    string fullName = ClassName + ", " + AssemblyDictionary[AssembName];
                    //   Type t = Type.GetType(fullName);
                    //   object v = JSerializer.Deserialize(t, Text);

                    var serializer = new JavaScriptSerializer();
                    //   serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
                    dynamic obj = serializer.Deserialize(Text, typeof(object));
                    Processed.Add(AssembName);
                }
            }
        }
Exemple #6
0
        private static Enum CreateEnum(string value)
        {
            if (AssemblyDictionary.EnumExists(value))
            {
                var  type = AssemblyDictionary.GetEnumByName(value);
                Enum e    = (Enum)System.Activator.CreateInstance(type);

                return(e);
            }
            else if (CR2WManager.EnumExists(value))
            {
                var  type = CR2WManager.GetEnumByName(value);
                Enum e    = (Enum)System.Activator.CreateInstance(type);

                return(e);
            }

            return(null);
        }
Exemple #7
0
        public void QueueObjects()
        {
            var objects = new ObjectInfo[m_exports.Length];

            for (int i = 0; i < m_exports.Length; i++)
            {
                var e = m_exports[i];

                var className = GetCName(e.className);
                var type      = AssemblyDictionary.GetTypeByName(className);
                if (type == null)
                {
                    throw new Exception($"Unknown Type: '{className}'");
                }

                BaseStream.Seek(e.dataOffset, SeekOrigin.Begin);
                var objData = ReadBytes((int)e.dataSize);
                if (!IgnoreErrors && Crc32Algorithm.Compute(objData) != e.crc32)
                {
                    throw new MismatchCRC32Exception();
                }

                var instance = Activator.CreateInstance(type);
                if (instance is CObject obj)
                {
                    obj.Template = e.template;
                    obj.Flags    = (ECObjectFlags)e.objectFlags;
                }

                objects[i] = new ObjectInfo()
                {
                    Instance = instance,
                    NameID   = e.className,
                    Data     = objData,
                };
            }
        }
Exemple #8
0
        private static (int, string) InterpretScriptClasses()
        {
            List <string> importedClasses = new List <string>();
            List <string> importedEnums   = new List <string>();
            string        output          = "";

            using (StringWriter sw = new StringWriter())
            {
                // usings and namespace
                sw.WriteLine(header);

                FileInfo[] projectScriptFiles = m_projectinfo.GetFiles("*.ws", SearchOption.AllDirectories);


                sw.WriteLine("\tpublic static partial class Enums");
                sw.WriteLine("\t{\r\n");
                // interpret enums
                #region Enums
                foreach (var file in projectScriptFiles)
                {
                    int    depth      = 0;
                    bool   isReading  = false;
                    string enumname   = "";
                    string enumstring = "";

                    var lines = File.ReadLines(file.FullName);
                    foreach (var line in lines)
                    {
                        // check if should start reading
                        if (line.Contains("enum "))
                        {
                            // interpret line
                            string intline = InterpretEnumLine(line, ref enumname);
                            if (!string.IsNullOrEmpty(intline))
                            {
                                // check if enum is vanilla
                                if (AssemblyDictionary.EnumExists(enumname))
                                {
                                    continue;
                                }
                                if (importedEnums.Contains(enumname))
                                {
                                    continue;
                                }

                                enumstring += $"\t{intline}\r\n";

                                isReading = true;
                            }

                            // increment or decrement the depth
                            depth += line.Count(_ => _ == '{');
                            depth -= line.Count(_ => _ == '}');
                            continue;
                        }

                        // if reading, interpret results
                        if (isReading)
                        {
                            // increment or decrement the depth
                            depth += line.Count(_ => _ == '{');
                            depth -= line.Count(_ => _ == '}');

                            // only interpret variables at depth 1 (from the class depth)
                            if (depth == 1)
                            {
                                if (!string.IsNullOrEmpty(line))
                                {
                                    var iline = InterpretEnumVarLine(line);
                                    if (!string.IsNullOrEmpty(iline))
                                    {
                                        enumstring += $"\t\t\t{iline}\r\n";
                                    }
                                }
                            }

                            // if depth is 0 again, stop reading and write to output
                            if (depth == 0)
                            {
                                sw.WriteLine(enumstring);
                                sw.WriteLine("\t\t}");

                                isReading  = false;
                                enumstring = "";
                                importedEnums.Add(enumname);
                            }
                        }
                    }
                }
                #endregion
                sw.WriteLine("\t}\r\n");

                // interpret classes
                #region Classes
                foreach (var file in projectScriptFiles)
                {
                    int    depth       = 0;
                    bool   isReading   = false;
                    int    varcounter  = 0;
                    string classname   = "";
                    string classstring = "";

                    var lines = File.ReadLines(file.FullName);
                    foreach (var line in lines)
                    {
                        // check if should start reading
                        if (line.Contains("class "))
                        {
                            // interpret line
                            string intline = InterpretClassLine(line, ref classname);
                            if (!string.IsNullOrEmpty(intline))
                            {
                                // check if class is vanilla
                                if (AssemblyDictionary.TypeExists(classname))
                                {
                                    continue;
                                }
                                if (importedClasses.Contains(classname))
                                {
                                    continue;
                                }

                                classstring += $"{intline}\r\n";

                                isReading = true;
                            }

                            // increment or decrement the depth
                            depth += line.Count(_ => _ == '{');
                            depth -= line.Count(_ => _ == '}');
                            continue;
                        }

                        // if reading, interpret results
                        if (isReading)
                        {
                            // increment or decrement the depth
                            depth += line.Count(_ => _ == '{');
                            depth -= line.Count(_ => _ == '}');

                            // only interpret variables at depth 1 (from the class depth)
                            if (depth == 1)
                            {
                                string intline = InterpretVarLine(line, varcounter, importedEnums);
                                if (!string.IsNullOrEmpty(intline))
                                {
                                    classstring += $"{intline}";
                                    varcounter++;
                                }
                            }

                            // if depth is 0 again, stop reading and write to output
                            if (depth == 0)
                            {
                                sw.WriteLine(classstring);
                                sw.WriteLine(funcCtor(classname));
                                sw.WriteLine(footer);

                                varcounter  = 0;
                                isReading   = false;
                                classstring = "";
                                importedClasses.Add(classname);
                            }
                        }
                    }
                }
                #endregion


                // namespace end
                sw.WriteLine("}");
                output = sw.ToString();
            }

            if (importedClasses.Count > 0)
            {
                if (m_logger != null)
                {
                    m_logger.LogString($"Sucessfully parsed {importedClasses.Count} custom classes: " +
                                       $"{string.Join(", ", importedClasses)}", Logtype.Success);
                }
            }
            return(importedClasses.Count, output);
        }
Exemple #9
0
        void ParseVariale(string type, int size, string offset)
        {
            var arr = type.Split(new char[] { ':' }, 2);

            switch (arr[0])
            {
                #region .NET Types
            case "Uint8":
            {
                Writer.WriteLine(" {0}", ReadByte());
            }
                return;

            case "Uint16":
            {
                Writer.WriteLine(" {0}", ReadUInt16());
            }
                return;

            case "Uint32":
            {
                Writer.WriteLine(" {0}", ReadUInt32());
            }
                return;

            case "Uint64":
            {
                Writer.WriteLine(" {0}", ReadUInt64());
            }
                return;

            case "Int8":
            {
                Writer.WriteLine(" {0}", ReadSByte());
            }
                return;

            case "Int16":
            {
                Writer.WriteLine(" {0}", ReadInt16());
            }
                return;

            case "Int32":
            {
                Writer.WriteLine(" {0}", ReadInt32());
            }
                return;

            case "Int64":
            {
                Writer.WriteLine(" {0}", ReadInt64());
            }
                return;

            case "Float":
            {
                Writer.WriteLine(" {0}", ReadSingle());
            }
                return;

            case "String":
            {
                var(flag, length) = ReadVLQInt32();
                var encoding = flag ? Encoding.ASCII : Encoding.Unicode;
                var chars    = new char[length];
                var byteSize = encoding.GetByteCount(chars);
                var bytes    = ReadBytes(byteSize);
                encoding.GetChars(bytes, 0, byteSize, chars, 0);
                Writer.WriteLine(" {0}", new string(chars));
            }
                return;

            case "Bool":
            {
                Writer.WriteLine(" {0}", ReadBoolean());
            }
                return;

                #endregion
                #region RED Types
            case "StringAnsi":
            {
                var length = ReadByte();
                var bytes  = ReadBytes(length);
                Writer.WriteLine(" {0}", new StringAnsi(bytes));
            }
                return;

            case "CName":
            {
                Writer.WriteLine(" {0}", names[ReadUInt16()].Value);
            }
                return;

            case "CGUID":
            {
                Writer.WriteLine(" {0}", new CGUID(ReadBytes(16)).ToString());
            }
                return;

            case "LocalizedString":
            {
                Writer.WriteLine(" {0}", ReadUInt32());
            }
                return;

            case "ptr":
            {
                Writer.WriteLine(" Object {0}", ReadUInt32());
            }
                return;

            case "soft":
            {
                var id = ReadUInt16();
                if (id == 0)
                {
                    Writer.WriteLine(" NULL");
                    return;
                }
                var res = resources[id - 1];
                Writer.WriteLine(" {0} {1} ({2})", res.Type, res.Path, res.Flags);
            }
                return;

            case "array":
            {
                arr = arr[1].Split(new char[] { ',' }, 3);
                var len = ReadUInt32();
                Writer.WriteLine(" {0}", len);
                Writer.WriteLine("{0}{{", offset.Substring(1));
                for (uint i = 0; i < len; i++)
                {
                    Writer.Write("{0}Id {1}:", offset, i);
                    ParseVariale(arr[2], size, $"\t{offset}");
                }
                Writer.WriteLine("{0}}}", offset.Substring(1));
            }
                return;

            case "handle":
            {
                var id = ReadInt32();
                if (id >= 0)
                {
                    Writer.WriteLine(" Object: {0}", id);
                }
                else
                {
                    id *= -1;
                    var res = resources[id - 1];
                    Writer.WriteLine(" {0} {1} ({2})", res.Type, res.Path, res.Flags);
                }
            }
                return;

            case "SAppearanceAttachment":
            {
                Writer.WriteLine();
                Writer.WriteLine("{0}{{", offset.Substring(1));
                ReadVariable(offset);
                var bytecount = ReadInt32();
                var unknown   = ReadBytes(bytecount - 4);
                Writer.WriteLine("{0}Unknown Bytes: {1}", offset, bytecount - 4);
                Writer.WriteLine("{0}}}", offset.Substring(1));
            }
                return;

            case "IdTag":
            {
                var dynamic = ReadBoolean();
                var guid    = new CGUID(ReadBytes(16));
                if (dynamic)
                {
                    Writer.WriteLine(" [Dynamic: {0}]", guid.ToString());
                }
                else
                {
                    Writer.WriteLine(" [Static: {0}]", guid.ToString());
                }
            }
                return;

            case "EngineTransform":
            {
                Writer.Write(" [ ");
                var flags = ReadByte();
                if ((flags & 1) == 1)
                {
                    Writer.Write("Posistion:{0},{1},{2} ", ReadSingle(), ReadSingle(), ReadSingle());
                }
                if ((flags & 2) == 2)
                {
                    Writer.Write("Rotation:{0},{1},{2} ", ReadSingle(), ReadSingle(), ReadSingle());
                }
                if ((flags & 4) == 4)
                {
                    Writer.Write("Scale:{0},{1},{2} ", ReadSingle(), ReadSingle(), ReadSingle());
                }
                Writer.WriteLine("]");
            }
                return;

            case "EngineQsTransform":
            {
                Writer.Write(" [ ");
                var flags = ReadByte();
                if ((flags & 1) == 1)
                {
                    Writer.Write("Posistion:{0},{1},{2} ", ReadSingle(), ReadSingle(), ReadSingle());
                }
                if ((flags & 2) == 2)
                {
                    Writer.Write("Rotation:{0},{1},{2},{3} ", ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle());
                }
                if ((flags & 4) == 4)
                {
                    Writer.Write("Scale:{0},{1},{2} ", ReadSingle(), ReadSingle(), ReadSingle());
                }
                Writer.WriteLine("]");
            }
                return;

            case "TagList":
            {
                // This could be a vlq int value but so far there is no tag list
                // size big enough to use more than one bytes.
                var count = ReadByte();
                var tags  = new string[count];
                for (var i = 0; i < count; i++)
                {
                    tags[i] = names[ReadUInt16()].Value;
                }
                Writer.WriteLine(" [{0}]", string.Join(",", tags));
            }
                return;

            case "EntityHandle":
            {
                /*
                 *  Read the first byte which will tell you what type of entity handle it is.
                 *  Values:
                 *      0 - None - 0 bytes
                 *      1 - Entity Guid - 32 bytes
                 *      2 - IdTag - 17 bytes
                 *
                 *      Then read off that variable type.
                 *
                 *      IdTag:
                 *          1 Byte - 0 = Static, 1 = Dynamic
                 *          16 Bytes - Guid Value
                 *      Entity:
                 *          16 Bytes - Guid Value
                 *          16 Bytes - Unknown
                 */
                var handletype = ReadByte();
                switch (handletype)
                {
                //Entity
                case 1:
                    var eguid = new CGUID(ReadBytes(16));
                    var unkn  = ReadBytes(16);
                    Writer.WriteLine(" [Entity - {0}]", eguid.ToString());
                    break;

                //IdTag
                case 2:
                    var dynamic = ReadBoolean();
                    var guid    = new CGUID(ReadBytes(16));
                    if (dynamic)
                    {
                        Writer.WriteLine(" [Dynamic: {0}]", guid.ToString());
                    }
                    else
                    {
                        Writer.WriteLine(" [Static: {0}]", guid.ToString());
                    }
                    break;
                }
            }
                return;

            case "static":
            {
                var length = ReadUInt32();
                arr = arr[1].Split(new char[] { ',' }, 2);
                Writer.WriteLine(" {0}", length);
                Writer.WriteLine("{0}{{", offset.Substring(1));
                for (uint i = 0; i < length; i++)
                {
                    Writer.Write("{0}Id {1}:", offset, i);
                    ParseVariale(arr[1], size, $"\t{offset}");
                }
                Writer.WriteLine("{0}}}", offset.Substring(1));
            }
                return;

            case "CDateTime":
            {
                var datetime = new CDateTime(ReadUInt64());
                Writer.WriteLine(" {0}.{1}", datetime.ToString(), datetime.Value.Millisecond);
            }
                return;

            case "SharedDataBuffer":
            {
                var datasize = ReadInt32();
                var bytes    = ReadBytes(datasize);
                Writer.WriteLine(" {0} bytes", datasize);
            }
                return;

            case "DataBuffer":
            {
                var datasize = ReadInt32();
                var bytes    = ReadBytes(datasize);
                Writer.WriteLine(" {0} bytes", datasize);
            }
                return;

            case "DeferredDataBuffer":
            {
                Writer.WriteLine(" {0}", ReadUInt16());
            }
                return;

            case "SMeshTypeResourceLODLevel":
            {
                Writer.WriteLine(" {0}", ReadSingle());
            }
                return;

            case "CPhysicalCollision":
            {
                var unknown   = ReadUInt32();
                var nameCount = ReadByte();

                Writer.WriteLine();
                Writer.WriteLine("{0}{{", offset.Substring(1));
                Writer.WriteLine("{0}unknown Uint32 {1}", offset, unknown);
                Writer.WriteLine("{0}Types", offset);
                Writer.WriteLine("{0}{{", offset);
                for (byte i = 0; i < nameCount; i++)
                {
                    Writer.WriteLine("\t{0}Id {1}: {2}", offset, i, names[ReadUInt16()].Value);
                }
                Writer.WriteLine("{0}}}", offset);
                Writer.WriteLine("{0}Bytes {1}", offset, String.Join(", ", ReadBytes(16)));
                Writer.WriteLine("{0}}}", offset.Substring(1));
            }
                return;

                #endregion
            }

            //Detects types such as [7]Float etc...
            var regEx = Regex.Match(type, @"^\[([0-9]+)\]([\x00-\x7F]+)$");
            if (regEx.Success)
            {
                var arraySize = ReadUInt32();
                if (arraySize != Convert.ToUInt32(regEx.Groups[1].Value))
                {
                    throw new FormatException();
                }
                Writer.WriteLine(" {0}", arraySize);
                Writer.WriteLine("{0}{{", offset.Substring(1));
                for (uint i = 0; i < arraySize; i++)
                {
                    Writer.Write("{0}Id {1}:", offset, i);
                    ParseVariale(regEx.Groups[2].Value, size, $"\t{offset}");
                }
                Writer.WriteLine("{0}}}", offset.Substring(1));
                return;
            }

            var myType = AssemblyDictionary.GetTypeByName(type);
            if (myType != null && myType.IsEnum)
            {
                if (myType.IsDefined(typeof(FlagsAttribute), false))
                {
                    var values = new List <string>();
                    while (true)
                    {
                        var flag = ReadUInt16();
                        if (flag == 0)
                        {
                            break;
                        }
                        values.Add(names[flag].Value);
                    }
                    if (values.Count != 0)
                    {
                        Writer.WriteLine(" {0}", Enum.Parse(myType, String.Join(",", values)));
                    }
                    else
                    {
                        Writer.WriteLine(" {0}", "None");
                    }
                }
                else
                {
                    var value = names[ReadUInt16()].Value;
                    Writer.WriteLine(" {0}", value);
                }
                return;
            }

            Writer.WriteLine();
            Writer.WriteLine("{0}{{", offset.Substring(1));
            ReadVariable(offset);
            Writer.WriteLine("{0}}}", offset.Substring(1));
        }
Exemple #10
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
        }
        /// <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
        }