/// <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 NotImplementedException(); } } #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 }
private (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 Enums 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 Classes // namespace end sw.WriteLine("}"); output = sw.ToString(); } if (importedClasses.Count > 0) { _loggerService.Success($"Sucessfully parsed {importedClasses.Count} custom classes: " + $"{string.Join(", ", importedClasses)}"); } return(importedClasses.Count, output); }
/// <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, IWolvenkitFile 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 as IRed3EngineFile, parentVariable as CVariable, 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); IREDArray arrayacc = MakeArray(typeof(CArray <>), innerobject.GetType()); arrayacc.Flags = new List <int>() { int.Parse(flag1), int.Parse(flag2) }; if (innerobject is IREDArray accessor && accessor.Flags != null) { arrayacc.Flags.AddRange(accessor.Flags); } arrayacc.Elementtype = body; return(arrayacc as CVariable); } else { CVariable innerobject = Create(innertype, "", cr2w, null); IREDArray 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. Error code: {fullname}"); return(Create("SItem", varname, cr2w, parentVariable)); } 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. Error code: {fullname}"); return(Create("handle:CEnvironmentDefinition", varname, cr2w, parentVariable)); } 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 as IRed3EngineFile, parentVariable, $"UNKNOWN:{typename}:{varname}")); } else { return(null); } } } #region LOCAL FUNCTIONS IREDArray 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 IREDArray); } 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 }