Fixed patch for extension data (#577)
Co-authored-by: Alex <clodanSPT@hotmail.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SPTarkov.Server.Core.Utils.Reference;
|
||||
|
||||
// This class is used by the JsonExtensionDataPatch, dont remove!
|
||||
public class StaticReferences
|
||||
{
|
||||
[JsonIgnore]
|
||||
private Dictionary<string, object> _reference = new();
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, object> Reference
|
||||
{
|
||||
get { return _reference; }
|
||||
}
|
||||
}
|
||||
@@ -9,53 +9,15 @@ public class JsonExtensionDataPatch : IPatcher
|
||||
{
|
||||
private TypeReference? _dictionaryStringObjectReference;
|
||||
|
||||
private MethodReference? _dictionaryStringObjectCtorReference;
|
||||
private MethodReference? _jsonExtensionDataAttributeReference;
|
||||
|
||||
private MethodReference? _jsonIgnoreAttributeReference;
|
||||
|
||||
public void Patch(AssemblyDefinition assembly)
|
||||
{
|
||||
_dictionaryStringObjectReference ??= assembly.MainModule.ImportReference(typeof(Dictionary<string, object>));
|
||||
_dictionaryStringObjectCtorReference ??= assembly.MainModule.ImportReference(
|
||||
typeof(Dictionary<string, object>).GetConstructor(Type.EmptyTypes)
|
||||
);
|
||||
var sptReferenceType = assembly.MainModule.Types.First(t => t.FullName == "SPTarkov.Server.Core.Utils.Reference.StaticReferences");
|
||||
var propertyReferenceType = sptReferenceType.Properties.First(p => p.Name == "Reference");
|
||||
var fieldReferenceType = sptReferenceType.Fields.First(p => p.Name == "_reference");
|
||||
_dictionaryStringObjectReference = propertyReferenceType.PropertyType;
|
||||
|
||||
if (_jsonExtensionDataAttributeReference is null)
|
||||
{
|
||||
var jsonConstructorReference = assembly
|
||||
.MainModule.AssemblyResolver.Resolve(AssemblyNameReference.Parse("System.Text.Json"))
|
||||
.MainModule.GetType("System.Text.Json.Serialization.JsonExtensionDataAttribute")
|
||||
.Methods.First(m => m.IsConstructor && !m.HasParameters);
|
||||
|
||||
_jsonExtensionDataAttributeReference = assembly.MainModule.ImportReference(jsonConstructorReference);
|
||||
}
|
||||
|
||||
if (_jsonIgnoreAttributeReference is null)
|
||||
{
|
||||
var jsonIgnoreConstructorReference = assembly
|
||||
.MainModule.AssemblyResolver.Resolve(AssemblyNameReference.Parse("System.Text.Json"))
|
||||
.MainModule.GetType("System.Text.Json.Serialization.JsonIgnoreAttribute")
|
||||
.Methods.First(m => m.IsConstructor && !m.HasParameters);
|
||||
|
||||
_jsonIgnoreAttributeReference = assembly.MainModule.ImportReference(jsonIgnoreConstructorReference);
|
||||
}
|
||||
var isExternalInitType = assembly.MainModule.ImportReference(typeof(System.Runtime.CompilerServices.IsExternalInit));
|
||||
|
||||
var compilerGenerated = assembly.MainModule.ImportReference(
|
||||
assembly.MainModule.ImportReference(
|
||||
typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes)
|
||||
)
|
||||
);
|
||||
|
||||
var nullableAttrType = assembly.MainModule.ImportReference(typeof(System.Runtime.CompilerServices.NullableAttribute));
|
||||
var attrCtor = assembly.MainModule.ImportReference(
|
||||
nullableAttrType
|
||||
.Resolve()
|
||||
.Methods.First(m => m.IsConstructor && m.Parameters.Count == 1 && m.Parameters[0].ParameterType.Name == "Byte")
|
||||
);
|
||||
var attr = new CustomAttribute(attrCtor);
|
||||
attr.ConstructorArguments.Add(new CustomAttributeArgument(assembly.MainModule.TypeSystem.Byte, (byte)1));
|
||||
// We need to steal from the constructor the IL line 2 (index 1)
|
||||
var createDictionaryReference = sptReferenceType.GetConstructors().First(c => c.Parameters.Count == 0).Body.Instructions[1];
|
||||
|
||||
var processed = new HashSet<string>();
|
||||
foreach (var typeDefinition in assembly.MainModule.Types)
|
||||
@@ -66,23 +28,23 @@ public class JsonExtensionDataPatch : IPatcher
|
||||
|| typeDefinition.IsEnum
|
||||
|| IsStaticClass(typeDefinition)
|
||||
|| processed.Contains(typeDefinition.FullName)
|
||||
|| typeDefinition.IsAbstract
|
||||
|| typeDefinition.HasGenericParameters
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var propertyDefinition = new PropertyDefinition("ExtensionData", PropertyAttributes.None, _dictionaryStringObjectReference);
|
||||
propertyDefinition.CustomAttributes.Add(new CustomAttribute(_jsonExtensionDataAttributeReference));
|
||||
propertyDefinition.CustomAttributes.Add(attr);
|
||||
propertyDefinition.CustomAttributes.Add(propertyReferenceType.CustomAttributes.First());
|
||||
|
||||
// Add backing field
|
||||
var field = new FieldDefinition(
|
||||
"<ExtensionData>k__BackingField",
|
||||
"_extensionData",
|
||||
FieldAttributes.Private | FieldAttributes.InitOnly,
|
||||
_dictionaryStringObjectReference
|
||||
);
|
||||
field.CustomAttributes.Add(new CustomAttribute(compilerGenerated));
|
||||
field.CustomAttributes.Add(attr);
|
||||
field.CustomAttributes.Add(fieldReferenceType.CustomAttributes.First());
|
||||
typeDefinition.Fields.Add(field);
|
||||
|
||||
// Add getter
|
||||
@@ -92,35 +54,13 @@ public class JsonExtensionDataPatch : IPatcher
|
||||
_dictionaryStringObjectReference
|
||||
);
|
||||
|
||||
get.CustomAttributes.Add(new CustomAttribute(compilerGenerated));
|
||||
get.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
|
||||
get.Body.Instructions.Add(Instruction.Create(OpCodes.Ldfld, field));
|
||||
get.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
|
||||
propertyDefinition.GetMethod = get;
|
||||
|
||||
typeDefinition.Methods.Add(get);
|
||||
|
||||
// Add setter
|
||||
var set = new MethodDefinition(
|
||||
"set_ExtensionData",
|
||||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||||
assembly.MainModule.TypeSystem.Void
|
||||
);
|
||||
|
||||
var returnType = set.ReturnType;
|
||||
var modifiedReturnType = new RequiredModifierType(isExternalInitType, returnType);
|
||||
set.MethodReturnType.ReturnType = modifiedReturnType;
|
||||
set.CustomAttributes.Add(new CustomAttribute(compilerGenerated));
|
||||
set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, _dictionaryStringObjectReference));
|
||||
set.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
|
||||
set.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
|
||||
set.Body.Instructions.Add(Instruction.Create(OpCodes.Stfld, field));
|
||||
set.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
|
||||
propertyDefinition.SetMethod = set;
|
||||
|
||||
typeDefinition.Methods.Add(set);
|
||||
typeDefinition.Properties.Add(propertyDefinition);
|
||||
|
||||
foreach (var methodDefinition in typeDefinition.GetConstructors().Where(c => !c.IsStatic))
|
||||
@@ -128,7 +68,7 @@ public class JsonExtensionDataPatch : IPatcher
|
||||
var ilCtor = methodDefinition.Body.GetILProcessor();
|
||||
|
||||
var loadArg = ilCtor.Create(OpCodes.Ldarg_0);
|
||||
var createObj = ilCtor.Create(OpCodes.Newobj, _dictionaryStringObjectCtorReference);
|
||||
var createObj = createDictionaryReference;
|
||||
var setField = ilCtor.Create(OpCodes.Stfld, field);
|
||||
var first = ilCtor.Body.Instructions.First();
|
||||
ilCtor.InsertBefore(first, loadArg);
|
||||
|
||||
Reference in New Issue
Block a user