243 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.IO;
 | |
| using System.Linq;
 | |
| using System.Text.Json;
 | |
| using EpicGames.UHT.Types;
 | |
| using UnrealSharpScriptGenerator.Model;
 | |
| 
 | |
| namespace UnrealSharpScriptGenerator.PropertyTranslators;
 | |
| 
 | |
| public static class PropertyTranslatorManager
 | |
| {
 | |
|     private static readonly Dictionary<Type, List<PropertyTranslator>?> RegisteredTranslators = new();
 | |
|     private static readonly HashSet<Type> RegisteredPrimitives = new();
 | |
|     private static readonly HashSet<Type> RegisteredNumerics = new();
 | |
| 
 | |
|     public static SpecialTypeInfo SpecialTypeInfo { get; } = new();
 | |
|     
 | |
|     static PropertyTranslatorManager()
 | |
|     {
 | |
|         var projectDirectory = Program.Factory.Session.ProjectDirectory;
 | |
|         var configDirectory = Path.Combine(projectDirectory!, "Config");
 | |
|         
 | |
|         var pluginDirectory = Path.Combine(projectDirectory!, "Plugins");
 | |
|         var pluginDirInfo = new DirectoryInfo(pluginDirectory);
 | |
| 
 | |
|         var files = pluginDirInfo.GetFiles("*.uplugin", SearchOption.AllDirectories)
 | |
|             .Select(x => x.DirectoryName!)
 | |
|             .Select(x => Path.Combine(x, "Config"))
 | |
|             .Concat(new List<string> { configDirectory })
 | |
|             .Select(x => new DirectoryInfo(x))
 | |
|             .Where(x => x.Exists)
 | |
|             .SelectMany(x => x.GetFiles("*.UnrealSharpTypes.json", SearchOption.AllDirectories))
 | |
|             .Select(x => x.FullName);
 | |
|         foreach (var pluginFile in files)
 | |
|         {
 | |
|             using var fileStream = File.OpenRead(pluginFile);
 | |
|             try
 | |
|             {
 | |
|                 var manifest = JsonSerializer.Deserialize<TypeTranslationManifest>(fileStream);
 | |
|                 AddTranslationManifest(manifest!);
 | |
|             }
 | |
|             catch (JsonException e)
 | |
|             {
 | |
|                 Console.WriteLine($"Error reading {pluginFile}: {e.Message}");
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         EnumPropertyTranslator enumPropertyTranslator = new();
 | |
|         AddPropertyTranslator(typeof(UhtEnumProperty), enumPropertyTranslator);
 | |
|         AddPropertyTranslator(typeof(UhtByteProperty), enumPropertyTranslator);
 | |
|         
 | |
|         AddBlittablePropertyTranslator(typeof(UhtInt8Property), "sbyte", PropertyKind.SByte);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtInt16Property), "short", PropertyKind.Short);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtInt64Property), "long", PropertyKind.Long);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtUInt16Property), "ushort", PropertyKind.UShort);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtUInt32Property), "uint", PropertyKind.UInt);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtUInt64Property), "ulong", PropertyKind.ULong);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtDoubleProperty), "double", PropertyKind.Double);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtByteProperty), "byte", PropertyKind.Byte);
 | |
|         AddBlittablePropertyTranslator(typeof(UhtLargeWorldCoordinatesRealProperty), "double", PropertyKind.Double);
 | |
|         AddPropertyTranslator(typeof(UhtFloatProperty), new FloatPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtIntProperty), new IntPropertyTranslator());
 | |
| 
 | |
|         MulticastDelegatePropertyTranslator multicastDelegatePropertyTranslator = new();
 | |
|         AddPropertyTranslator(typeof(UhtMulticastSparseDelegateProperty), multicastDelegatePropertyTranslator);
 | |
|         AddPropertyTranslator(typeof(UhtMulticastDelegateProperty), multicastDelegatePropertyTranslator);
 | |
|         AddPropertyTranslator(typeof(UhtMulticastInlineDelegateProperty), multicastDelegatePropertyTranslator);
 | |
|         AddPropertyTranslator(typeof(UhtDelegateProperty), new SinglecastDelegatePropertyTranslator());
 | |
|         
 | |
|         AddBlittablePropertyTranslator(typeof(UhtByteProperty), "byte", PropertyKind.Byte);
 | |
|         
 | |
|         AddPropertyTranslator(typeof(UhtBoolProperty), new BoolPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtStrProperty), new StringPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtNameProperty), new NamePropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtTextProperty), new TextPropertyTranslator());
 | |
|         
 | |
|         AddPropertyTranslator(typeof(UhtWeakObjectPtrProperty), new WeakObjectPropertyTranslator());
 | |
|         
 | |
|         WorldContextObjectPropertyTranslator worldContextObjectPropertyTranslator = new();
 | |
|         AddPropertyTranslator(typeof(UhtObjectPropertyBase), worldContextObjectPropertyTranslator);
 | |
| #if !UE_5_6_OR_LATER
 | |
|         AddPropertyTranslator(typeof(UhtObjectPtrProperty), worldContextObjectPropertyTranslator);
 | |
| #endif
 | |
|         AddPropertyTranslator(typeof(UhtObjectProperty), worldContextObjectPropertyTranslator);
 | |
|         AddPropertyTranslator(typeof(UhtLazyObjectPtrProperty), worldContextObjectPropertyTranslator);
 | |
|         
 | |
|         ObjectPropertyTranslator objectPropertyTranslator = new();
 | |
|         AddPropertyTranslator(typeof(UhtObjectPropertyBase), objectPropertyTranslator);
 | |
| #if !UE_5_6_OR_LATER
 | |
|         AddPropertyTranslator(typeof(UhtObjectPtrProperty), objectPropertyTranslator);
 | |
| #endif
 | |
|         AddPropertyTranslator(typeof(UhtObjectProperty), objectPropertyTranslator);
 | |
|         AddPropertyTranslator(typeof(UhtLazyObjectPtrProperty), objectPropertyTranslator);
 | |
|         
 | |
|         AddPropertyTranslator(typeof(UhtInterfaceProperty), new InterfacePropertyTranslator());
 | |
|         
 | |
|         AddPropertyTranslator(typeof(UhtClassProperty), new ClassPropertyTranslator());
 | |
| #if !UE_5_6_OR_LATER
 | |
|         AddPropertyTranslator(typeof(UhtClassPtrProperty), new ClassPropertyTranslator());
 | |
| #endif
 | |
|         AddPropertyTranslator(typeof(UhtSoftClassProperty), new SoftClassPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtSoftObjectProperty), new SoftObjectPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtFieldPathProperty), new FieldPathPropertyTranslator());
 | |
| 
 | |
|         foreach (var (nativeName, managedType) in SpecialTypeInfo.Structs.BlittableTypes.Values)
 | |
|         {
 | |
|             if (managedType is null)
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             AddBlittableCustomStructPropertyTranslator(nativeName, managedType);
 | |
|         }
 | |
| 
 | |
|         AddPropertyTranslator(typeof(UhtArrayProperty), new ArrayPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtMapProperty), new MapPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtSetProperty), new SetPropertyTranslator());
 | |
|         
 | |
|         AddPropertyTranslator(typeof(UhtStructProperty), new BlittableStructPropertyTranslator());
 | |
|         AddPropertyTranslator(typeof(UhtStructProperty), new StructPropertyTranslator());
 | |
|         
 | |
|         AddPropertyTranslator(typeof(UhtOptionalProperty), new OptionalPropertyTranslator());
 | |
|         
 | |
|         // Manually exported properties
 | |
|         InclusionLists.BanProperty("UWorld", "GameState");
 | |
|         InclusionLists.BanProperty("UWorld", "AuthorityGameMode");
 | |
| 
 | |
|         // Some reason == equality differs from .Equals
 | |
|         InclusionLists.BanEquality("FRandomStream");
 | |
| 
 | |
|         // Renamed variables X/Y/Z to Pitch/Yaw/Roll
 | |
|         InclusionLists.BanEquality("FRotator");
 | |
| 
 | |
|         // Fields not generating correctly
 | |
|         InclusionLists.BanEquality("FVector3f");
 | |
|         InclusionLists.BanEquality("FVector2f");
 | |
|         InclusionLists.BanEquality("FVector4f");
 | |
|         InclusionLists.BanEquality("FVector_NetQuantize");
 | |
|         InclusionLists.BanEquality("FVector_NetQuantize10");
 | |
|         InclusionLists.BanEquality("FVector_NetQuantize100");
 | |
|         InclusionLists.BanEquality("FVector_NetQuantizeNormal");
 | |
| 
 | |
|         // Doesn't have any fields
 | |
|         InclusionLists.BanEquality("FSubsystemCollectionBaseRef");
 | |
| 
 | |
|         // Custom arithmetic needed
 | |
|         InclusionLists.BanArithmetic("FQuat");
 | |
|     }
 | |
| 
 | |
|     public static void AddTranslationManifest(TypeTranslationManifest manifest)
 | |
|     {
 | |
|         foreach (var skippedStruct in manifest.Structs.CustomTypes)
 | |
|         {
 | |
|             SpecialTypeInfo.Structs.SkippedTypes.Add(skippedStruct);
 | |
|         }
 | |
|         
 | |
|         foreach (var structInfo in manifest.Structs.BlittableTypes)
 | |
|         {
 | |
|             if (SpecialTypeInfo.Structs.NativelyCopyableTypes.ContainsKey(structInfo.Name))
 | |
|             {
 | |
|                 throw new InvalidOperationException(
 | |
|                     $"A struct cannot be both blittable and natively copyable: {structInfo.Name}");
 | |
|             }
 | |
|             
 | |
|             if (SpecialTypeInfo.Structs.BlittableTypes.TryGetValue(structInfo.Name, out var existing))
 | |
|             {
 | |
|                 if (structInfo.ManagedType is not null && existing.ManagedType is not null &&
 | |
|                     structInfo.ManagedType != existing.ManagedType)
 | |
|                 {
 | |
|                     throw new InvalidOperationException($"Duplicate struct name specified: {structInfo.Name}");
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 SpecialTypeInfo.Structs.BlittableTypes.Add(structInfo.Name, structInfo);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         foreach (var structInfo in manifest.Structs.NativelyTranslatableTypes)
 | |
|         {
 | |
|             if (SpecialTypeInfo.Structs.NativelyCopyableTypes.TryGetValue(structInfo.Name, out var existing))
 | |
|             {
 | |
|                 SpecialTypeInfo.Structs.NativelyCopyableTypes[structInfo.Name] = existing with { HasDestructor = existing.HasDestructor || structInfo.HasDestructor };
 | |
|                 continue;
 | |
|             }
 | |
|             
 | |
|             if (SpecialTypeInfo.Structs.BlittableTypes.ContainsKey(structInfo.Name))
 | |
|             {
 | |
|                 throw new InvalidOperationException(
 | |
|                     $"A struct cannot be both blittable and natively copyable: {structInfo.Name}");
 | |
|             }
 | |
| 
 | |
|             SpecialTypeInfo.Structs.NativelyCopyableTypes.Add(structInfo.Name, structInfo);
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     public static PropertyTranslator? GetTranslator(UhtProperty property)
 | |
|     {
 | |
|         if (!RegisteredTranslators.TryGetValue(property.GetType(), out var translator))
 | |
|         {
 | |
|             return null;
 | |
|         }
 | |
|         
 | |
|         foreach (PropertyTranslator propertyTranslator in translator!)
 | |
|         {
 | |
|             if (propertyTranslator.CanExport(property))
 | |
|             {
 | |
|                 return propertyTranslator;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         return null;
 | |
|     }
 | |
|     
 | |
|     public static void AddBlittablePropertyTranslator(Type propertyType, string managedType, PropertyKind propertyKind = PropertyKind.Unknown)
 | |
|     {
 | |
|         if (RegisteredTranslators.TryGetValue(propertyType, out var translators))
 | |
|         {
 | |
|             translators!.Add(new BlittableTypePropertyTranslator(propertyType, managedType, propertyKind));
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         RegisteredTranslators.Add(propertyType, new List<PropertyTranslator> {new BlittableTypePropertyTranslator(propertyType, managedType, propertyKind) });
 | |
|     }
 | |
| 
 | |
|     private static void AddPropertyTranslator(Type propertyClass, PropertyTranslator translator)
 | |
|     {
 | |
|         if (RegisteredTranslators.TryGetValue(propertyClass, out var translators))
 | |
|         {
 | |
|             translators!.Add(translator);
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         RegisteredTranslators.Add(propertyClass, new List<PropertyTranslator> {translator});
 | |
|     }
 | |
|     
 | |
|     private static void AddBlittableCustomStructPropertyTranslator(string nativeName, string managedType)
 | |
|     {
 | |
|         AddPropertyTranslator(typeof(UhtStructProperty), new BlittableCustomStructTypePropertyTranslator(nativeName, managedType));
 | |
|     }
 | |
| }
 |