Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,6 @@ GameAssembly.dll
libil2cpp.so
*.fbs

.idea
.idea

_DONT/
19 changes: 9 additions & 10 deletions Assembly/AttributeExtractor.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
using Mono.Cecil;
using Mono.Collections.Generic;
using dnlib.DotNet;
using ZLinq;

namespace MemoryPackDumper.Assembly;

public static class AttributeExtractor
{
public static void ExtractClassAttributes(TypeDefinition typeDef, MemoryPackClass memoryPackClass)
public static void ExtractClassAttributes(TypeDef typeDef, MemoryPackClass memoryPackClass)
{
foreach (var attr in typeDef.CustomAttributes)
switch (attr.AttributeType.Name)
Expand Down Expand Up @@ -38,8 +37,8 @@ private static void ExtractMemoryPackableAttribute(CustomAttribute attr, MemoryP
}
else
{
var layoutProp = attr.Properties.FirstOrDefault(p => p.Name == "SerializeLayout");
if (layoutProp.Argument.Value != null)
var layoutProp = attr.NamedArguments.FirstOrDefault(p => p.Name == "SerializeLayout");
if (layoutProp is { Argument.Value: not null })
memoryPackClass.SerializeLayout = EnumMapper.MapSerializeLayout(layoutProp.Argument.Value.ToString()!);
}
}
Expand All @@ -49,11 +48,11 @@ private static void ExtractMemoryPackUnionAttribute(CustomAttribute attr, Memory
if (attr.ConstructorArguments.Count < 2) return;

var tag = Convert.ToInt32(attr.ConstructorArguments[0].Value);
if (attr.ConstructorArguments[1].Value is TypeReference typeRef)
memoryPackClass.Unions.Add(new MemoryPackUnion(tag, typeRef.Name));
if (attr.ConstructorArguments[1].Value is TypeSig typeSig)
memoryPackClass.Unions.Add(new MemoryPackUnion(tag, typeSig.ReflectionName));
}

public static void ExtractMemberAttributes(Collection<CustomAttribute> attributes, MemoryPackMember member)
public static void ExtractMemberAttributes(CustomAttributeCollection attributes, MemoryPackMember member)
{
foreach (var attr in attributes)
switch (attr.AttributeType.Name)
Expand Down Expand Up @@ -94,11 +93,11 @@ public static void ExtractMemberAttributes(Collection<CustomAttribute> attribute
}
}

public static void ExtractMethodAttributes(MethodDefinition methodDef, MemoryPackMethod method)
public static void ExtractMethodAttributes(MethodDef methodDef, MemoryPackMethod method)
{
foreach (var attr in methodDef.CustomAttributes.AsValueEnumerable())
{
var attrName = attr.AttributeType.Name;
var attrName = attr.AttributeType.Name.String;

if (attrName is "TokenAttribute" or "AddressAttribute" or "FieldOffsetAttribute")
continue;
Expand Down
114 changes: 66 additions & 48 deletions Assembly/MemberParser.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using MemoryPackDumper.Helpers;
using Mono.Cecil;
using dnlib.DotNet;
using MemoryPackDumper.Context;
using ZLinq;

namespace MemoryPackDumper.Assembly;

public static class MemberParser
{
public static MemoryPackClass TypeToMemoryPackClass(TypeDefinition typeDef, HashSet<string> discoveredTypes)
public static MemoryPackClass TypeToMemoryPackClass(TypeDef typeDef, HashSet<string> discoveredTypes)
{
var className = GetClassName(typeDef);
var typeKeyword = TypeHelper.GetTypeKeyword(typeDef);
Expand All @@ -29,28 +29,28 @@ public static MemoryPackClass TypeToMemoryPackClass(TypeDefinition typeDef, Hash
return memoryPackClass;
}

private static string GetClassName(TypeDefinition typeDef)
private static string GetClassName(TypeDef typeDef)
{
var name = typeDef.Name;
var name = typeDef.Name.String;

if (!typeDef.HasGenericParameters)
return name;

if (name.Contains('`'))
name = name[..name.IndexOf('`')];

var genericParams = typeDef.GenericParameters.AsValueEnumerable().Select(p => p.Name).JoinToString(", ");
var genericParams = typeDef.GenericParameters.AsValueEnumerable().Select(p => p.Name.String).JoinToString(", ");
return $"{name}<{genericParams}>";
}

private static bool IsRecordType(TypeDefinition typeDef)
private static bool IsRecordType(TypeDef typeDef)
{
return typeDef.CustomAttributes.AsValueEnumerable().Any(a =>
a.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute") ||
typeDef.BaseType?.Name == "Record";
(typeDef.BaseType != null && typeDef.BaseType.Name == "Record");
}

private static void ProcessProperties(TypeDefinition typeDef, MemoryPackClass memoryPackClass,
private static void ProcessProperties(TypeDef typeDef, MemoryPackClass memoryPackClass,
HashSet<string> discoveredTypes)
{
foreach (var property in typeDef.Properties)
Expand All @@ -66,10 +66,11 @@ private static void ProcessProperties(TypeDefinition typeDef, MemoryPackClass me
}
}

private static void ProcessFields(TypeDefinition typeDef, MemoryPackClass memoryPackClass,
private static void ProcessFields(TypeDef typeDef, MemoryPackClass memoryPackClass,
HashSet<string> discoveredTypes)
{
foreach (var field in typeDef.Fields.AsValueEnumerable().Where(f => !f.IsStatic && !f.IsLiteral))
foreach (var field in typeDef.Fields.AsValueEnumerable()
.Where(f => !f.IsStatic && !f.IsLiteral && !IsCompilerGeneratedBackingField(f)))
{
var member = CreateMemberFromField(field);
if (!ShouldIncludeMember(member, field.IsPublic)) continue;
Expand All @@ -79,8 +80,15 @@ private static void ProcessFields(TypeDefinition typeDef, MemoryPackClass memory
}
}

private static bool IsCompilerGeneratedBackingField(FieldDef field)
{
var name = field.Name.String;
return name.StartsWith('<') && name.EndsWith(">k__BackingField");
}

private static bool ShouldIncludeMember(MemoryPackMember member, bool isPublic)
{
if (ParserOptionsContext.current.allowHidden) return !member.IsIgnored;
return member.IsInclude || (!member.IsIgnored && isPublic);
}

Expand All @@ -100,7 +108,7 @@ private static void SortMembersByOrder(MemoryPackClass memoryPackClass)
});
}

private static void ProcessMethods(TypeDefinition typeDef, MemoryPackClass memoryPackClass)
private static void ProcessMethods(TypeDef typeDef, MemoryPackClass memoryPackClass)
{
foreach (var method in typeDef.Methods)
{
Expand All @@ -112,31 +120,28 @@ private static void ProcessMethods(TypeDefinition typeDef, MemoryPackClass memor
}
}

private static bool IsMemoryPackMethod(MethodDefinition method)
private static bool IsMemoryPackMethod(MethodDef method)
{
return IsMemoryPackConstructor(method) || IsCallbackMethod(method) || IsStaticConstructor(method) ||
IsOverrideMethod(method);
}

private static bool IsOverrideMethod(MethodDefinition method)
private static bool IsOverrideMethod(MethodDef method)
{
if (method is not { IsVirtual: true, IsNewSlot: false, IsGetter: false, IsSetter: false })
return false;

if (method.Name is "Serialize" or "Deserialize")
return false;

return true;
return method.Name != "Serialize" && method.Name != "Deserialize";
}

private static bool IsMemoryPackConstructor(MethodDefinition method)
private static bool IsMemoryPackConstructor(MethodDef method)
{
return method.IsConstructor &&
method.CustomAttributes.AsValueEnumerable()
.Any(a => a.AttributeType.Name == "MemoryPackConstructorAttribute");
}

private static bool IsCallbackMethod(MethodDefinition method)
private static bool IsCallbackMethod(MethodDef method)
{
return method.CustomAttributes.AsValueEnumerable().Any(a =>
a.AttributeType.Name == "MemoryPackOnSerializingAttribute" ||
Expand All @@ -145,14 +150,15 @@ private static bool IsCallbackMethod(MethodDefinition method)
a.AttributeType.Name == "MemoryPackOnDeserializedAttribute");
}

private static bool IsStaticConstructor(MethodDefinition method)
private static bool IsStaticConstructor(MethodDef method)
{
return method is { IsStatic: true, Name: "StaticConstructor" } &&
return method is { IsStatic: true } &&
method.Name.String == "StaticConstructor" &&
method.ReturnType.FullName == "System.Void" &&
method.Parameters.Count == 0;
}

private static MemoryPackMethod CreateMethodFromDefinition(MethodDefinition methodDef)
private static MemoryPackMethod CreateMethodFromDefinition(MethodDef methodDef)
{
var returnType = TypeStringConverter.TypeToString(methodDef.ReturnType);
var visibility = GetMethodVisibility(methodDef);
Expand All @@ -167,14 +173,16 @@ private static MemoryPackMethod CreateMethodFromDefinition(MethodDefinition meth

foreach (var param in methodDef.Parameters)
{
var paramType = TypeStringConverter.TypeToString(param.ParameterType);
if (param.IsHiddenThisParameter) continue;

var paramType = TypeStringConverter.TypeToString(param.Type);
method.Parameters.Add((paramType, param.Name));
}

return method;
}

private static string GetMethodVisibility(MethodDefinition methodDef)
private static string GetMethodVisibility(MethodDef methodDef)
{
if (methodDef.IsPublic) return "public";
if (methodDef.IsFamily) return "protected";
Expand All @@ -184,18 +192,18 @@ private static string GetMethodVisibility(MethodDefinition methodDef)
return "private";
}

private static MemoryPackMember CreateMemberFromProperty(PropertyDefinition property)
private static MemoryPackMember CreateMemberFromProperty(PropertyDef property)
{
var accessorMethod = property.GetMethod ?? property.SetMethod;
var member = new MemoryPackMember(property.Name, property.PropertyType, false)
var member = new MemoryPackMember(property.Name, property.PropertySig.RetType, false)
{
IsPublic = accessorMethod?.IsPublic ?? false
};
AttributeExtractor.ExtractMemberAttributes(property.CustomAttributes, member);
return member;
}

private static MemoryPackMember CreateMemberFromField(FieldDefinition field)
private static MemoryPackMember CreateMemberFromField(FieldDef field)
{
var member = new MemoryPackMember(field.Name, field.FieldType, true)
{
Expand All @@ -205,33 +213,44 @@ private static MemoryPackMember CreateMemberFromField(FieldDefinition field)
return member;
}

public static MemoryPackEnum TypeToEnum(TypeDefinition typeDef)
public static MemoryPackEnum TypeToEnum(TypeDef typeDef)
{
var underlyingType = GetEnumUnderlyingType(typeDef);
var memoryPackEnum = new MemoryPackEnum(underlyingType, typeDef.Name)
var underlyingTypeName = GetEnumUnderlyingTypeName(typeDef);
var memoryPackEnum = new MemoryPackEnum(underlyingTypeName, typeDef.Name)
{
OriginalNamespace = typeDef.Namespace ?? ""
};

foreach (var fieldDef in typeDef.Fields.AsValueEnumerable().Where(f => f.HasConstant))
{
var enumField = new MemoryPackEnumField(fieldDef.Name, Convert.ToInt64(fieldDef.Constant));
var enumField = new MemoryPackEnumField(fieldDef.Name, Convert.ToInt64(fieldDef.Constant.Value));
memoryPackEnum.Fields.Add(enumField);
}

return memoryPackEnum;
}

private static TypeDefinition GetEnumUnderlyingType(TypeDefinition typeDef)
private static string GetEnumUnderlyingTypeName(TypeDef typeDef)
{
var underlyingType = typeDef.Fields.FirstOrDefault(f => f.Name == "value__")?.FieldType.Resolve();
if (underlyingType != null) return underlyingType;
var valueField = typeDef.Fields.FirstOrDefault(f => f.Name == "value__");
if (valueField != null)
return valueField.FieldType.FullName switch
{
"System.Byte" => "byte",
"System.SByte" => "sbyte",
"System.Int16" => "short",
"System.UInt16" => "ushort",
"System.Int32" => "int",
"System.UInt32" => "uint",
"System.Int64" => "long",
"System.UInt64" => "ulong",
_ => "int"
};

Log.Warning($"Could not determine underlying type for enum {typeDef.FullName}");
return typeDef.Module.TypeSystem.Int32.Resolve();
return "int";
}

private static void ProcessNestedTypes(TypeDefinition typeDef, MemoryPackClass memoryPackClass,
private static void ProcessNestedTypes(TypeDef typeDef, MemoryPackClass memoryPackClass,
HashSet<string> discoveredTypes)
{
if (!typeDef.HasNestedTypes) return;
Expand All @@ -249,22 +268,21 @@ private static void ProcessNestedTypes(TypeDefinition typeDef, MemoryPackClass m
}
}

private static bool IsAutoGeneratedFormatter(TypeDefinition nestedType, string parentClassName)
private static bool IsAutoGeneratedFormatter(TypeDef nestedType, string parentClassName)
{
if (nestedType.BaseType == null) return false;

var baseTypeName = nestedType.BaseType.Name;
var baseTypeName = nestedType.BaseType.Name.String;
if (!baseTypeName.StartsWith("MemoryPackFormatter")) return false;

if (nestedType.BaseType is GenericInstanceType genericBase && genericBase.GenericArguments.Count > 0)
{
var formattedTypeName = genericBase.GenericArguments[0].Name;
var parentBaseName = parentClassName.Contains('<')
? parentClassName[..parentClassName.IndexOf('<')]
: parentClassName;
if (nestedType.BaseType is not TypeSpec { TypeSig: GenericInstSig genericBase } ||
genericBase.GenericArguments.Count <= 0) return false;
var formattedTypeName = genericBase.GenericArguments[0].TypeName;
var parentBaseName = parentClassName.Contains('<')
? parentClassName[..parentClassName.IndexOf('<')]
: parentClassName;

if (formattedTypeName == parentBaseName) return true;
}
if (formattedTypeName == parentBaseName) return true;

return false;
}
Expand Down
14 changes: 7 additions & 7 deletions Assembly/MemoryPackTypes.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Mono.Cecil;
using dnlib.DotNet;

namespace MemoryPackDumper.Assembly;

Expand All @@ -17,10 +17,10 @@ public class MemoryPackClass(string className, string baseClassName, string type
public readonly List<MemoryPackMethod> Methods = [];
public readonly string TypeKeyword = typeKeyword;
public readonly List<MemoryPackUnion> Unions = [];
public TypeReference? BaseTypeReference = null;
public ITypeDefOrRef? BaseTypeReference = null;
public string? GenerateType = null;
public bool IsRecord = false;
public List<MemoryPackClass> NestedClasses = [];
public readonly List<MemoryPackClass> NestedClasses = [];
public string OriginalNamespace = "";
public string? SerializeLayout = null;
}
Expand All @@ -42,12 +42,12 @@ public class MemoryPackUnion(int tag, string typeName)
public readonly string TypeName = typeName;
}

public class MemoryPackMember(string name, TypeReference type, bool isField)
public class MemoryPackMember(string name, TypeSig type, bool isField)
{
public readonly List<string> CustomFormatters = [];
public readonly bool IsField = isField;
public readonly string Name = name;
public readonly TypeReference Type = type;
public readonly TypeSig Type = type;
public bool AllowSerialize = false;
public bool IsIgnored = false;
public bool IsInclude = false;
Expand All @@ -59,11 +59,11 @@ public class MemoryPackMember(string name, TypeReference type, bool isField)
public bool SuppressDefaultInitialization = false;
}

public class MemoryPackEnum(TypeDefinition valueType, string enumName)
public class MemoryPackEnum(string underlyingType, string enumName)
{
public readonly string EnumName = enumName;
public readonly List<MemoryPackEnumField> Fields = [];
public readonly TypeDefinition Type = valueType;
public readonly string UnderlyingType = underlyingType;
public string OriginalNamespace = "";
}

Expand Down
Loading
Loading