public static NMSTemplate DeserializeEXml(EXmlData xmlData) { NMSTemplate template = TemplateFromName(xmlData.Template); Type templateType = template.GetType(); var templateFields = templateType.GetFields().OrderBy(field => field.MetadataToken); // hack to get fields in order of declaration (todo: use something less hacky, this might break mono?) foreach (var templateField in templateFields) { NMSAttribute settings = templateField.GetCustomAttribute <NMSAttribute>(); if (settings?.DefaultValue != null) { templateField.SetValue(template, settings.DefaultValue); } } foreach (var xmlProperty in xmlData.Elements.OfType <EXmlProperty>()) { FieldInfo field = templateType.GetField(xmlProperty.Name); Type fieldType = field.FieldType; NMSAttribute settings = field.GetCustomAttribute <NMSAttribute>(); object fieldValue = DeserializeEXmlValue(template, fieldType, field, xmlProperty, templateType, settings); field.SetValue(template, fieldValue); } foreach (EXmlData innerXmlData in xmlData.Elements.OfType <EXmlData>()) { FieldInfo field = templateType.GetField(innerXmlData.Name); NMSTemplate innerTemplate = DeserializeEXml(innerXmlData); field.SetValue(template, innerTemplate); } return(template); }
public static NMSTemplate DeserializeBinaryTemplate(BinaryReader reader, string templateName) { if (templateName.StartsWith("c") && templateName.Length > 1) { templateName = templateName.Substring(1); } NMSTemplate obj = TemplateFromName(templateName); if (obj == null) { return(null); } long templatePosition = reader.BaseStream.Position; if (PrintToDebug) { Debug.WriteLine($"{templateName} position: 0x{templatePosition:X}"); } if (templateName == "VariableSizeString") { long stringPos = reader.ReadInt64(); int stringLength = reader.ReadInt32(); int unkC = reader.ReadInt32(); reader.BaseStream.Position = templatePosition + stringPos; ((VariableSizeString)obj).Value = reader.ReadString(Encoding.UTF8, stringLength); reader.BaseStream.Position = templatePosition + 0x10; return(obj); } var type = obj.GetType(); var fields = type.GetFields().OrderBy(field => field.MetadataToken); // hack to get fields in order of declaration (todo: use something less hacky, this might break mono?) foreach (var field in fields) { NMSAttribute settings = field.GetCustomAttribute <NMSAttribute>(); field.SetValue(obj, DeserializeValue(reader, field.FieldType, settings, templatePosition, field, obj)); } obj.FinishDeserialize(); if (PrintToDebug) { Debug.WriteLine($"{templateName} end position: 0x{reader.BaseStream.Position:X}"); } return(obj); }
public static NMSTemplate DeserializeEXml(EXmlData xmlData) { NMSTemplate template = TemplateFromName(xmlData.Template); Type templateType = template.GetType(); foreach (var xmlProperty in xmlData.Elements.OfType <EXmlProperty>()) { FieldInfo field = templateType.GetField(xmlProperty.Name); Type fieldType = field.FieldType; object fieldValue; switch (fieldType.Name) { case "String": fieldValue = xmlProperty.Value; break; case "Single": fieldValue = float.Parse(xmlProperty.Value); break; case "Boolean": fieldValue = bool.Parse(xmlProperty.Value); break; case "Int16": fieldValue = short.Parse(xmlProperty.Value); break; case "Int32": var valuesMethod = templateType.GetMethod(field.Name + "Values"); if (valuesMethod != null) { if (String.IsNullOrEmpty(xmlProperty.Value)) { fieldValue = (int)-1; } else { string[] values = (string[])valuesMethod.Invoke(template, null); fieldValue = Array.FindIndex(values, v => v == xmlProperty.Value); } } else { fieldValue = int.Parse(xmlProperty.Value); } break; case "Int64": fieldValue = long.Parse(xmlProperty.Value); break; case "Byte[]": fieldValue = xmlProperty.Value == null ? null : Convert.FromBase64String(xmlProperty.Value); break; case "List`1": Type elementType = fieldType.GetGenericArguments()[0]; Type listType = typeof(List <>).MakeGenericType(elementType); IList list = (IList)Activator.CreateInstance(listType); foreach (EXmlData innerXmlData in xmlProperty.Elements.OfType <EXmlData>()) { NMSTemplate element = DeserializeEXml(innerXmlData); list.Add(element); } fieldValue = list; break; default: fieldValue = fieldType.IsValueType ? Activator.CreateInstance(fieldType) : null; break; } field.SetValue(template, fieldValue); } foreach (EXmlData innerXmlData in xmlData.Elements.OfType <EXmlData>()) { FieldInfo field = templateType.GetField(innerXmlData.Name); NMSTemplate innerTemplate = DeserializeEXml(innerXmlData); field.SetValue(template, innerTemplate); } return(template); }
public static NMSTemplate DeserializeBinaryTemplate(BinaryReader reader, string templateName) { if (templateName.StartsWith("c") && templateName.Length > 1) { templateName = templateName.Substring(1); } NMSTemplate obj = TemplateFromName(templateName); if (obj == null) { return(null); } long templatePosition = reader.BaseStream.Position; System.Diagnostics.Debug.Print(templateName + " position: " + templatePosition.ToString("X")); if (templateName == "VariableSizeString") { long stringPos = reader.ReadInt64(); int stringLength = reader.ReadInt32(); int unkC = reader.ReadInt32(); reader.BaseStream.Position = templatePosition + stringPos; ((VariableSizeString)obj).Value = reader.ReadString(Encoding.UTF8, stringLength); reader.BaseStream.Position = templatePosition + 0x10; return(obj); } var type = obj.GetType(); var fields = type.GetFields().OrderBy(field => field.MetadataToken); // hack to get fields in order of declaration (todo: use something less hacky, this might break mono?) foreach (var field in fields) { var fieldAddr = reader.BaseStream.Position - templatePosition; var fieldName = field.Name; var fieldType = field.FieldType.Name; switch (fieldType) { case "String": case "Byte[]": int size = 0; foreach (var attr in field.CustomAttributes) { if (attr.AttributeType.Name != "MarshalAsAttribute") { continue; } foreach (var named in attr.NamedArguments) { if (named.MemberName != "SizeConst") { continue; } size = (int)named.TypedValue.Value; } } if (fieldType == "String") { // reader.Align(0x4, templatePosition); var str = reader.ReadString(Encoding.UTF8, size, true); field.SetValue(obj, str); } else { var str = reader.ReadBytes(size); field.SetValue(obj, str); } break; case "Single": reader.Align(4, 0); field.SetValue(obj, reader.ReadSingle()); break; case "Boolean": field.SetValue(obj, reader.ReadByte() != 0); break; case "Int16": case "UInt16": reader.Align(2, 0); field.SetValue(obj, fieldType == "Int16" ? reader.ReadInt16() : (object)reader.ReadUInt16()); break; case "Int32": case "UInt32": reader.Align(4, 0); field.SetValue(obj, fieldType == "Int32" ? reader.ReadInt32() : (object)reader.ReadUInt32()); break; case "Int64": case "UInt64": reader.Align(8, 0); field.SetValue(obj, fieldType == "Int64" ? reader.ReadInt64() : (object)reader.ReadUInt64()); break; case "List`1": reader.Align(8, 0); if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(List <>)) { Type itemType = field.FieldType.GetGenericArguments()[0]; // use this... if (itemType == typeof(NMSTemplate)) { field.SetValue(obj, DeserializeGenericList(reader, templatePosition)); } else { // todo: get rid of this nastiness MethodInfo method = typeof(NMSTemplate).GetMethod("DeserializeList", BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .MakeGenericMethod(new Type[] { itemType }); var list = method.Invoke(null, new object[] { reader, templatePosition }); field.SetValue(obj, list); } } break; case "NMSTemplate": reader.Align(8, 0); long startPos = reader.BaseStream.Position; long offset = reader.ReadInt64(); string name = reader.ReadString(Encoding.ASCII, 0x40, true); long endPos = reader.BaseStream.Position; if (offset != 0 && !String.IsNullOrEmpty(name)) { reader.BaseStream.Position = startPos + offset; NMSTemplate val = DeserializeBinaryTemplate(reader, name); if (val == null) { throw new Exception("Failed to deserialize template " + name + "!"); } field.SetValue(obj, val); } reader.BaseStream.Position = endPos; break; default: if (fieldType == "Colour") // unsure if this is needed? { reader.Align(0x10, 0); } // todo: align for VariableSizeString? var data = DeserializeBinaryTemplate(reader, fieldType); if (data != null) { field.SetValue(obj, data); } break; } } return(obj); }
public static NMSTemplate DeserializeEXml(EXmlData xmlData) { NMSTemplate template = TemplateFromName(xmlData.Template); Type templateType = template.GetType(); var templateFields = templateType.GetFields().OrderBy(field => field.MetadataToken); // hack to get fields in order of declaration (todo: use something less hacky, this might break mono?) foreach (var templateField in templateFields) { NMSAttribute settings = templateField.GetCustomAttribute <NMSAttribute>(); if (settings == null) { break; } if (settings.DefaultValue != null) { templateField.SetValue(template, settings.DefaultValue); } } foreach (var xmlProperty in xmlData.Elements.OfType <EXmlProperty>()) { FieldInfo field = templateType.GetField(xmlProperty.Name); Type fieldType = field.FieldType; NMSAttribute settings = field.GetCustomAttribute <NMSAttribute>(); if (settings == null) { settings = new NMSAttribute(); } object fieldValue; switch (fieldType.Name) { case "String": fieldValue = xmlProperty.Value; break; case "Single": fieldValue = float.Parse(xmlProperty.Value); break; case "Boolean": fieldValue = bool.Parse(xmlProperty.Value); break; case "Int16": fieldValue = short.Parse(xmlProperty.Value); break; case "Int32": var valuesMethod = templateType.GetMethod(field.Name + "Values"); if (valuesMethod != null) { if (String.IsNullOrEmpty(xmlProperty.Value)) { fieldValue = (int)-1; } else { string[] values = (string[])valuesMethod.Invoke(template, null); fieldValue = Array.FindIndex(values, v => v == xmlProperty.Value); } } else if (settings.EnumValue != null) { if (String.IsNullOrEmpty(xmlProperty.Value)) { fieldValue = (int)-1; } else { fieldValue = Array.FindIndex(settings.EnumValue, v => v == xmlProperty.Value); } } else { fieldValue = int.Parse(xmlProperty.Value); } break; case "Int64": fieldValue = long.Parse(xmlProperty.Value); break; case "Byte[]": fieldValue = xmlProperty.Value == null ? null : Convert.FromBase64String(xmlProperty.Value); break; case "List`1": Type elementType = fieldType.GetGenericArguments()[0]; Type listType = typeof(List <>).MakeGenericType(elementType); IList list = (IList)Activator.CreateInstance(listType); foreach (EXmlData innerXmlData in xmlProperty.Elements.OfType <EXmlData>()) { NMSTemplate element = DeserializeEXml(innerXmlData); list.Add(element); } fieldValue = list; break; default: if (field.FieldType.IsArray && field.FieldType.GetElementType().BaseType.Name == "NMSTemplate") { Array array = Array.CreateInstance(field.FieldType.GetElementType(), settings.Size); List <EXmlData> data = xmlProperty.Elements.OfType <EXmlData>().ToList(); for (int i = 0; i < data.Count; ++i) { NMSTemplate element = DeserializeEXml(data[i]); array.SetValue(element, i); } fieldValue = array; } else { fieldValue = fieldType.IsValueType ? Activator.CreateInstance(fieldType) : null; } break; } field.SetValue(template, fieldValue); } foreach (EXmlData innerXmlData in xmlData.Elements.OfType <EXmlData>()) { FieldInfo field = templateType.GetField(innerXmlData.Name); NMSTemplate innerTemplate = DeserializeEXml(innerXmlData); field.SetValue(template, innerTemplate); } return(template); }