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)); } }
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)..];
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); }
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); } }
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)); }
/// <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 }
public string ToVarString() { var wktype = REDReflection.GetWKitBaseTypeFromREDBaseType(Type); return($"[RED(\"{Name}\")] public {wktype} {Name.FirstCharToUpper()} {{ get; set; }}"); }
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); } } } }
/// <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 }