2024-06-26 14:45:54 -04:00
|
|
|
|
using dnlib.DotNet;
|
2024-06-22 01:27:34 -04:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2024-06-12 20:16:12 -04:00
|
|
|
|
|
2024-06-14 19:06:21 -04:00
|
|
|
|
namespace ReCodeIt.ReMapper;
|
2024-06-12 20:16:12 -04:00
|
|
|
|
|
2024-06-22 01:27:34 -04:00
|
|
|
|
internal static class SPTPublicizer
|
|
|
|
|
{
|
2024-06-26 14:45:54 -04:00
|
|
|
|
private static ModuleDefMD MainModule;
|
2024-06-22 01:27:34 -04:00
|
|
|
|
|
2024-11-02 22:08:27 -04:00
|
|
|
|
public static void PublicizeClasses(ModuleDefMD definition, bool isLauncher = false)
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
2024-06-26 14:45:54 -04:00
|
|
|
|
var types = definition.GetTypes();
|
2024-06-22 01:27:34 -04:00
|
|
|
|
|
|
|
|
|
foreach (var type in types)
|
|
|
|
|
{
|
|
|
|
|
if (type.IsNested) continue; // Nested types are handled when publicizing the parent type
|
|
|
|
|
|
2024-11-02 22:08:27 -04:00
|
|
|
|
PublicizeType(type, isLauncher);
|
2024-06-22 01:27:34 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 22:08:27 -04:00
|
|
|
|
private static void PublicizeType(TypeDef type, bool isLauncher)
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
|
|
|
|
// if (type.CustomAttributes.Any(a => a.AttributeType.Name ==
|
|
|
|
|
// nameof(CompilerGeneratedAttribute))) { return; }
|
2024-11-02 22:08:27 -04:00
|
|
|
|
|
2024-06-22 01:27:34 -04:00
|
|
|
|
if (!type.IsNested && !type.IsPublic || type.IsNested && !type.IsNestedPublic)
|
|
|
|
|
{
|
2024-07-02 19:01:46 -04:00
|
|
|
|
if (!type.Interfaces.Any(i => i.Interface.Name == "IEffect"))
|
|
|
|
|
{
|
|
|
|
|
type.Attributes &= ~TypeAttributes.VisibilityMask; // Remove all visibility mask attributes
|
|
|
|
|
type.Attributes |= type.IsNested ? TypeAttributes.NestedPublic : TypeAttributes.Public; // Apply a public visibility attribute
|
|
|
|
|
}
|
2024-06-22 01:27:34 -04:00
|
|
|
|
}
|
2024-11-02 22:08:27 -04:00
|
|
|
|
|
|
|
|
|
if (type.IsSealed && !isLauncher)
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
|
|
|
|
type.Attributes &= ~TypeAttributes.Sealed; // Remove the Sealed attribute if it exists
|
|
|
|
|
}
|
2024-11-02 22:08:27 -04:00
|
|
|
|
|
2024-06-22 01:27:34 -04:00
|
|
|
|
foreach (var method in type.Methods)
|
|
|
|
|
{
|
|
|
|
|
PublicizeMethod(method);
|
|
|
|
|
}
|
2024-11-02 22:08:27 -04:00
|
|
|
|
|
2024-06-22 01:27:34 -04:00
|
|
|
|
foreach (var property in type.Properties)
|
|
|
|
|
{
|
|
|
|
|
if (property.GetMethod != null) PublicizeMethod(property.GetMethod);
|
|
|
|
|
if (property.SetMethod != null) PublicizeMethod(property.SetMethod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// var eventNames = new HashSet<string>(type.Events.Select(e => e.Name)); foreach (var field
|
|
|
|
|
// in type.Fields) { if (eventNames.Contains(field.Name)) { continue; }
|
|
|
|
|
//
|
|
|
|
|
// // if (type.Name.StartsWith("GClass") || !type.Namespace.Contains("EFT") ||
|
|
|
|
|
// !type.Namespace.Contains("UI") || !string.IsNullOrWhiteSpace(type.Namespace)) // if
|
|
|
|
|
// (type.Namespace.Length > 0 && type.Namespace[0] > 'E') PublicizeField(field); }
|
2024-07-02 19:01:46 -04:00
|
|
|
|
|
2024-06-22 01:27:34 -04:00
|
|
|
|
// Workaround to not publicize some nested types that cannot be patched easily and cause
|
|
|
|
|
// issues Specifically, we want to find any type that implements the "IHealthController"
|
|
|
|
|
// interface and make sure none of it's nested types that implement "IEffect" are changed
|
2024-06-28 18:02:14 -04:00
|
|
|
|
/*
|
2024-06-26 14:45:54 -04:00
|
|
|
|
if (GetFlattenedInterfacesRecursive(type).Any(i => i.Interface.Name == "IHealthController"))
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
|
|
|
|
// Specifically, any type that implements the IHealthController interface needs to not
|
|
|
|
|
// publicize any nested types that implement the IEffect interface
|
2024-06-26 14:45:54 -04:00
|
|
|
|
nestedTypesToPublicize = type.NestedTypes.Where(t => t.IsAbstract || t.Interfaces.All(i => i.Interface.Name != "IEffect")).ToArray();
|
2024-06-22 01:27:34 -04:00
|
|
|
|
}
|
2024-06-28 18:02:14 -04:00
|
|
|
|
*/
|
2024-07-02 19:01:46 -04:00
|
|
|
|
foreach (var nestedType in type.NestedTypes)
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
2024-11-02 22:08:27 -04:00
|
|
|
|
PublicizeType(nestedType, isLauncher);
|
2024-06-22 01:27:34 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-26 14:45:54 -04:00
|
|
|
|
private static void PublicizeMethod(MethodDef method)
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
|
|
|
|
if (method.IsCompilerControlled /*|| method.CustomAttributes.Any(a => a.AttributeType.Name == nameof(CompilerGeneratedAttribute))*/)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (method.IsPublic) return;
|
|
|
|
|
|
|
|
|
|
// if (!CanPublicizeMethod(method)) return;
|
|
|
|
|
|
|
|
|
|
// Workaround to not publicize a specific method so the game doesn't crash
|
|
|
|
|
if (method.Name == "TryGetScreen") return;
|
|
|
|
|
|
|
|
|
|
method.Attributes &= ~MethodAttributes.MemberAccessMask;
|
|
|
|
|
method.Attributes |= MethodAttributes.Public;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unused for now - publicizing fields is tricky, as it often creates MonoBehaviour loading
|
|
|
|
|
// errors and prevents scenes from loading, most notably breaking the initial game loader scene
|
|
|
|
|
// and causing the game to CTD right after starting
|
2024-06-26 14:45:54 -04:00
|
|
|
|
private static void PublicizeField(FieldDef field)
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
|
|
|
|
if (field.CustomAttributes.Any(a => a.AttributeType.Name == nameof(CompilerGeneratedAttribute))
|
|
|
|
|
// || field.HasCustomAttributes
|
|
|
|
|
|| field.Name.StartsWith("delegate")
|
|
|
|
|
|| field.Name.Contains("__BackingField"))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (field.IsPublic || field.IsCompilerControlled || field.IsLiteral || field.IsStatic || field.IsInitOnly) return;
|
|
|
|
|
|
|
|
|
|
field.Attributes &= ~FieldAttributes.FieldAccessMask;
|
|
|
|
|
field.Attributes |= FieldAttributes.Public;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-26 14:45:54 -04:00
|
|
|
|
private static List<InterfaceImpl> GetFlattenedInterfacesRecursive(TypeDef type)
|
2024-06-22 01:27:34 -04:00
|
|
|
|
{
|
2024-06-26 14:45:54 -04:00
|
|
|
|
var interfaces = new List<InterfaceImpl>();
|
2024-06-22 01:27:34 -04:00
|
|
|
|
|
|
|
|
|
if (type is null) return interfaces;
|
|
|
|
|
|
|
|
|
|
if (type.Interfaces.Any())
|
|
|
|
|
{
|
|
|
|
|
interfaces.AddRange(type.Interfaces);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type.BaseType != null && !type.BaseType.Name.Contains("Object"))
|
|
|
|
|
{
|
2024-06-28 18:02:14 -04:00
|
|
|
|
var baseTypeDefinition = MainModule?.Find(type.BaseType).ResolveTypeDef();
|
2024-06-22 01:27:34 -04:00
|
|
|
|
var baseTypeInterfaces = GetFlattenedInterfacesRecursive(baseTypeDefinition);
|
|
|
|
|
|
|
|
|
|
if (baseTypeInterfaces.Any())
|
|
|
|
|
{
|
|
|
|
|
interfaces.AddRange(baseTypeInterfaces);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return interfaces;
|
|
|
|
|
}
|
2024-06-12 20:16:12 -04:00
|
|
|
|
}
|